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

Why does DataStore only save the Stats and not the BoolValues?

Asked by 6 years ago

Hi!

I can't get my DataStore script to save the Tools purchased. I don't know why. I don't get any error for it. The leaderstats save, the Tools do not. I've included my entire Leaderboard/DataStore script.

I've included two versions I've been advised to try for the DataStore, the first one tries to save it into a Folder, the second one checks for BoolValues, but neither one will save the Tools, just the leaderstats.

First attempt with a Folder:

game.Players.ChildAdded:connect(function(newPlayer)
    local stats = Instance.new('IntValue')
    stats.Name = 'leaderstats'

    local points = Instance.new('IntValue', stats)
    points.Name = 'Points'
    points.Value = 0

    local experience = Instance.new('IntValue', stats)
    experience.Name = 'EXP'
    experience.Value = 0

    local wins = Instance.new('IntValue', stats)
    wins.Name = 'Wins'
    wins.Value = 0

    local kills = Instance.new('IntValue', stats)
    kills.Name = 'Kills'
    kills.Value = 0

    local level = Instance.new('IntValue', stats)
    level.Name = 'Level'
    level.Value = 1



-- MAX HEALTH INCREASE
if newPlayer.Character and newPlayer.Character:FindFirstChild("Humanoid") then
    newPlayer.Character.Humanoid.MaxHealth = 100 + level.Value*10
end

level.Changed:connect(function(value)
    if newPlayer.Character and newPlayer.Character:FindFirstChild("Humanoid") then
        newPlayer.Character.Humanoid.MaxHealth = 100 + level.Value*10
    end
end)

newPlayer.CharacterAdded:connect(function(character)
    character:WaitForChild("Humanoid").MaxHealth = 100 + level.Value*10
end)


-- EXP NEEDED TO LEVEL UP   
experience.Changed:connect(function()
    local required=(level.Value*70) -- Number reflects the EXP points needed to level up.
    if experience.Value >= required then
        level.Value=level.Value+1
        experience.Value=experience.Value-required 
            end
end)    

--DATASTORE

    stats.Parent = newPlayer
    local datastore = game:GetService("DataStoreService"):GetDataStore(newPlayer.Name.."Stats")
    local tools = game.ServerStorage.ToolStorage;-- ADDED FOR TOOLS

    local stats = stats:GetChildren()
    for i = 1, #stats do           
        stats[i].Value = datastore:GetAsync(stats[i].Name)
        print("stat number "..i.." has been found")
    end

    local save_interval = 60 * 2 -- every 2 minutes
    wait(save_interval)

    while newPlayer.Parent do
        local stats = newPlayer.leaderstats:GetChildren()
        for i = 1, #stats do           
            datastore:SetAsync(stats[i].Name, stats[i].Value)
            print("stat number "..i.." has been auto-saved")
    end
        local data = false
    print("DataStoreBackSave1")
    newPlayer.CharacterAdded:connect(function(char) -- this will run everytime the Player's Character has been added in workspace.
        if not data then
            data = datastore:GetAsync(newPlayer.UserId);
        end

        if data then
            --If it does, loop and clone respective tools.
            for _,v in next,data do
                local tool = tools:FindFirstChild(v);
                if tool then
                    tool:Clone().Parent = newPlayer.Backpack;
                end
            end
        end
    end)
end

        wait(save_interval)
end)

game.Players.ChildRemoved:connect(function(oldPlayer)
    local datastore = game:GetService("DataStoreService"):GetDataStore(oldPlayer.Name.."Stats")

    local stats = oldPlayer.leaderstats:GetChildren()
    for i = 1, #stats do           
        datastore:SetAsync(stats[i].Name, stats[i].Value)
        print("stat number "..i.." has been saved")

     --Make a table to hold all the data
    local toolList = {};

    --Iterate through the backpack and fill the table in

    for _,v in next,oldPlayer.Backpack:GetChildren() do
        --Make sure it's actually a tool

        if v:IsA("Tool") or v:IsA("HopperBin") then
            toolList[#toolList+1] = v.Name;
        end
    end
    --Save the table

    datastore:SetAsync(oldPlayer.UserId,toolList);
end
print("DataStoreBackSave2")
end)

Second attempt with BoolValues:

stats.Parent = newPlayer

    local datastore = game:GetService("DataStoreService"):GetDataStore(newPlayer.Name.."Stats")

    local stats = stats:GetChildren()
    for i = 1, #stats do          
        stats[i].Value = datastore:GetAsync(stats[i].Name)
        print("stat number "..i.." has been found")
    end

    local save_interval = 60 * 2 -- every 2 minutes

    wait(save_interval)

    while newPlayer.Parent do
        local stats = newPlayer.leaderstats:GetChildren()
        for i = 1, #stats do           
            datastore:SetAsync(stats[i].Name, stats[i].Value)
            print("stat number "..i.." has been auto-saved")
        end

        wait(save_interval)
    end


newPlayer.PlayerGui:WaitForChild("HasM9").Changed:Connect(function()
if newPlayer.PlayerGui.HasM9.Value == true then
local DataStorem9 = game:GetService("DataStoreService"):GetDataStore("HasM9")
game.ServerStorage.ToolStorage.M9:Clone().Parent = newPlayer.Backpack
DataStorem9:SetAsync(newPlayer.userId, true)

end
end)


end)



game.Players.ChildRemoved:connect(function(oldPlayer)
    local datastore = game:GetService("DataStoreService"):GetDataStore(oldPlayer.Name.."Stats")

    local stats = oldPlayer.leaderstats:GetChildren()
    for i = 1, #stats do          
        datastore:SetAsync(stats[i].Name, stats[i].Value)
        print("stat number "..i.." has been saved")
end


oldPlayer.PlayerGui:WaitForChild("HasM9").Changed:Connect(function()
if oldPlayer.PlayerGui.HasM9.Value == true then
local DataStorem9 = game:GetService("DataStoreService"):GetDataStore("HasM9")
DataStorem9:SetAsync(oldPlayer.userId, true)

end
end)

end)

I could really appreciate some help here, this has been bothering me for months now. x.x

0
You should be able to. hiimgoodpack 2009 — 6y
0
I agree, but it doesn't. When the player dies, or leaves the game and returns, the item is no longer in their backpack. Never2Humble 90 — 6y
0
would you like to see my data store abnotaddable 920 — 6y
0
Sure! Would be happy to see one that saves the tools! :) Sent a friend request. Never2Humble 90 — 6y
View all comments (6 more)
0
will do tommorow as on my phone of now abnotaddable 920 — 6y
0
^ Many thanks good sir! :) Never2Humble 90 — 6y
0
https://uploadfiles.io/ <<read your roblox messages for instructions abnotaddable 920 — 6y
0
Ah! Saw this late, sent the message, uploaded the file - https://ufile.io/lswdu Never2Humble 90 — 6y
0
I uploaded on google drive because it was easier abnotaddable 920 — 6y

1 answer

Log in to vote
0
Answered by 6 years ago
Edited 6 years ago

Unfortunately, your question was a bit more complex than I though it was, but I am sure I can still answer it.
Step 1. You want to create a folder of bool values in the player, each one named for ex: HasM9, HasM82 etc, each one should be false.
Then you want to create your data-store, I haven't changed mine to fit your question, but I have added lots of comments so you know what to do with the code.
Note : You should save tables on your keys, not individual values, each key can take alot, and it will lower how many times you access the data-store, lowering the chance of the data store budget being reached. Make sure to also use one datastore, not lots of datastores, unless each datastore holds different types of data, e.g XP datastore, Gun datastore etc. Your datastore should have a Unique name, this prevents the data you have saved being overwritten by data that has been saved in other games, also make sure your keys have unique names, and use Player.UserId, because if a player changes their name, they lose all of their data.
A Module script, in ServerScriptService

local module = {}
local DataStoreService = game:GetService("DataStoreService") --get DataStoreService
local InventoryItems = DataStoreService:GetDataStore("InventoryItems") --Change it to whatever you want to call it e.g :GetDataStore("examplename"), should be complex name
AUTOSAVE_INTERVAL = 120 --should be no lower than 60 (DataStore Budget)

game.Players.PlayerAdded:Connect(function(Player) --When a player is added to the game, load in their data
    local Key = 'PlayerIdNum-'..Player.UserId.."_InvItemKey" --"This is the key you use to save players data on (must be no longer than 50 characters and must be unique)
    --The key is also what you use to load data as well so it MUST be the exact same variable in the other parts of the script
    --Values to Save (create them also, e.g instance.new)
    local InvData = Player:WaitForChild("Backpack"):WaitForChild("Inventory") --The folder of values you want to save
    local Bananas = InvData:WaitForChild("Bananas")
    local Apples = InvData:WaitForChild("Apples")
    local FirstAid = InvData:WaitForChild("FirstAid")
    local Coconuts = InvData:WaitForChild("Coconuts")
    local MetalScraps = InvData:WaitForChild("MetalScraps")
    local Logs = InvData:WaitForChild("Logs")
    local Sticks = InvData:WaitForChild("Sticks")


    --DataStore Stuff
    --The table that is used to save it after it is all loaded in
    local StoreToSet = {}
    --Get the data and store it
    local DataToGet = InventoryItems:GetAsync(Key) --Returns the data the key stores (as a table)
    --Changing the table back into values
    if DataToGet ~= nil then --If there is a table
        if #DataToGet >= 1 then --If the table length is 1 or more
            print("Has Data")
            --For each value you have, copy the below code (MUST BE IN ORDER OF SAVED IN!)
            if DataToGet[1] ~= nil then --if the first bit of data in the table does exist
                Bananas.Value = DataToGet[1] --Set the values of bananas as that value
                table.insert(StoreToSet , DataToGet[1]) --Store it in another table so it can be saved
            end
            if DataToGet[2] ~= nil then
                Apples.Value = DataToGet[2]
                table.insert(StoreToSet , DataToGet[2])
            end
            if DataToGet[3] ~= nil then
                FirstAid.Value = DataToGet[3]
                table.insert(StoreToSet , DataToGet[3])
            end
            if DataToGet[4] ~= nil then
                Coconuts.Value = DataToGet[4]
                table.insert(StoreToSet , DataToGet[4])
            end
            if DataToGet[5] ~= nil then
                MetalScraps.Value = DataToGet[5]
                table.insert(StoreToSet , DataToGet[5])
            end
            if DataToGet[6] ~= nil then
                Logs.Value = DataToGet[6]
                table.insert(StoreToSet , DataToGet[6])
            end
            if DataToGet[7] ~= nil then
                Sticks.Value = DataToGet[7]
                table.insert(StoreToSet , DataToGet[7])
            end
        print(DataToGet[1], DataToGet[2], DataToGet[3], DataToGet[4], DataToGet[5], DataToGet[6], DataToGet[7] .. " Data") --Print the data values
        end
    else
        DataToGet = {} --Create a table, since there was no data or table returned in the GetAsync (this only happens with new players)
        DataToGet[1] = Bananas.Value --The first bit of data in the table is equal to Bananas.Value
        Bananas.Value = 0 --Make sure it is 0
        table.insert(StoreToSet , DataToGet[1]) --Insert it into table, so it can be saved, so next time they join, it loads a table
        DataToGet[2] = Apples.Value
        Apples.Value = 0
        table.insert(StoreToSet , DataToGet[2])
        DataToGet[3] = FirstAid.Value
        FirstAid.Value = 0
        table.insert(StoreToSet , DataToGet[3])
        DataToGet[4] = Coconuts.Value
        Coconuts.Value = 0
        table.insert(StoreToSet , DataToGet[4])
        DataToGet[5] = MetalScraps.Value
        MetalScraps.Value = 0
        table.insert(StoreToSet , DataToGet[5])
        DataToGet[6] = Logs.Value
        Logs.Value = 0
        table.insert(StoreToSet , DataToGet[6])
        DataToGet[7] = Sticks.Value
        Sticks.Value = 0
        table.insert(StoreToSet , DataToGet[7])
        print(DataToGet[1], DataToGet[2], DataToGet[3], DataToGet[4], DataToGet[5], DataToGet[6], DataToGet[7] .. " New Data") --Print new data (all should be 0)
    end
    InventoryItems:SetAsync(Key, StoreToSet) --Set the data to the key as a table, so next time they join there is a table to load in (only affects the first time they join)
end)

game.Players.PlayerRemoving:Connect(function(Player) --When the player leaves the game, save their data
    local Key = 'PlayerIdNum-'..Player.UserId.."_InvItemKey" --"This is the key you use to save players data on (must be no longer than 50 characters and must be unique)
    --The key is also what you use to load data as well so it MUST be the exact same variable in the other parts of the script
    --Values to Save
    local InvData = Player:WaitForChild("Backpack"):WaitForChild("Inventory")
    local Bananas = InvData:WaitForChild("Bananas")
    local Apples = InvData:WaitForChild("Apples")
    local FirstAid = InvData:WaitForChild("FirstAid")
    local Coconuts = InvData:WaitForChild("Coconuts")
    local MetalScraps = InvData:WaitForChild("MetalScraps")
    local Logs = InvData:WaitForChild("Logs")
    local Sticks = InvData:WaitForChild("Sticks")
    --Put what you need to save here (THE ORDER YOU USE IN THIS IS THE ORDER YOU MUST USE WHEN THEY JOIN)
    local DataToSave = {
        Bananas.Value, --must put.Value after or it will error
        Apples.Value,
        FirstAid.Value,
        Coconuts.Value,
        MetalScraps.Value,
        Logs.Value,
        Sticks.Value,
    }
    InventoryItems:SetAsync(Key, DataToSave)
end)

--You may want to reorder this
--Autosaving
spawn(function()
    while wait(AUTOSAVE_INTERVAL) do
        for i, Player in pairs (game:GetService("Players"):GetChildren()) do --for every player in the game, save
            print("Auto-saving " .. Player.Name .. "'s Data")
            local Key = 'PlayerIdNum-'..Player.UserId.."_InvItemKey"
            local InvData = Player:WaitForChild("Backpack"):WaitForChild("Inventory")
            local Bananas = InvData:WaitForChild("Bananas")
            local Apples = InvData:WaitForChild("Apples")
            local FirstAid = InvData:WaitForChild("FirstAid")
            local Coconuts = InvData:WaitForChild("Coconuts")
            local MetalScraps = InvData:WaitForChild("MetalScraps")
            local Logs = InvData:WaitForChild("Logs")
            local Sticks = InvData:WaitForChild("Sticks")
            local DataToSave = {
                Bananas.Value,
                Apples.Value,
                FirstAid.Value,
                Coconuts.Value,
                MetalScraps.Value,
                Logs.Value,
                Sticks.Value,
            }
            InventoryItems:SetAsync(Key, DataToSave)
            print("Successfully Auto-saved " .. Player.Name .. "'s Data")
        end
    end
end)

return module

A normal script, but a child/decendent of/inside of the module script

require(script.Parent)

After this, you will want another script that reads the values and gives them the tools based on the bool value, e.g:(local)

local player = game.Players.LocalPlayer
if player.Folder.HasM9.Value == true then
    local m9 = game.replicatedstorage.M9:Clone()
    m9.Parent = player.Backpack
end

I hope you can edit the script I have provided, to help you with your problem, if it has helped, please remember to accept the answer! :)

0
Good sir, thank you for this amazing response. I've followed your instructions, changed what needed to be changed, but unfortunately, its still not saving the items. I feel the error must be on me here, as your script looks excellent and makes sense. Line 10 and Line 120, per the DevConsole is where my script ends, "Stack End". The message I receive is - Never2Humble 90 — 6y
0
"Infinite yield possible on 'Players.PlayerName.Backpack:WaitForChild("Inventory")' I wonder if the problem is due to me storing the values inside a folder named 'Inventory' inside PlayerGui? Is there a different way I should phrase it? Never2Humble 90 — 6y
0
Wait, do I also need a Custom Inventory for this script to work properly? Never2Humble 90 — 6y
0
I just put it as a folder inside of player with the valus in it not custom just make sure everything is spelled correctly and in the write place e.g you said it was playergui so you would do Player:WaitForChild ("PlayerGui"):WaitForChild ("Inventory") but make sure that the folder is called Inventory and its spelled correctly abnotaddable 920 — 6y
View all comments (10 more)
0
Thanks for the response, I made sure it says Player:WaitForChild ("PlayerGui"):WaitForChild ("Inventory") , same error, Stack is ending on it at Line10, I made sure the Inventory folder inside PlayerGui with the Values is spelled correctly. The BoolValues are successfully enabling when purchased, and stay enabled after player death, but even when the Tool can be seen inside StarterGear, it doesn't Never2Humble 90 — 6y
0
clone back into the backpack. Or save when the player leaves the game and return. Also getting an error for that third script, which I named "ToolGiverCheck": 19:52:27.371 - ServerScriptService.ToolsDataStore.ToolGiverCheck:2: attempt to index local 'player' (a nil value) Do I need to keep that script apart from the ToolsDataStore? Never2Humble 90 — 6y
0
Keep the last script seperate (its meant to be in the player, and be a local script) and I reccomemd you put inventory folder in the players backpack (put it in starterpack, if not creating with instance .new) abnotaddable 920 — 6y
0
If you accept this answer and create a new question with all of your scripts and say where everything is located I can help you more abnotaddable 920 — 6y
0
And just noticed your previous comment, pasted the link above - https://ufile.io/lswdu Never2Humble 90 — 6y
0
I sent you a message on Roblox, but still having some problems here. :( It doesn't recognize StarterPack as a valid member of Player. Never2Humble 90 — 6y
0
Thats because starterpaxk isn't park of plaer. it is backpack in player. abnotaddable 920 — 6y
0
Excellent! Okay,in the ToolGiverCheck that was getting hung up, I replaced the "StarterPack" with "Backpack". The script no longer stopped, but it keeps cloning the purchased Tool until the player dies. XD; Aside from that, its still not saving the Tools, or the Stats now, once a player dies/leaves the game. Never2Humble 90 — 6y
1
I really don't know then. Best to create a new question with all your new code abnotaddable 920 — 6y
0
I will do that (edit: have)! Thank you very much for all your help! :) Couldn't have gotten this far without you! Never2Humble 90 — 6y
Ad

Answer this question