How to save a pet inventory inside a DataStore

Hello Everybody,

So I have a pet inventory and I was wondering if it was possible to save that Inventory inside a data. When the player leaves I want the pets to still be there. I will explain how the Inventory works now.
The Inventory is set up like this. (Look below)
Screenshot 2022-08-11 190627
So you have the Inventory GUI then you have the Lower InvFrame which is basically there to be a border and enhance the looks. Inside that is a scrolling frame which is self explanatory, Inside that is where the templates are stored(Pet images, a script parents the template there) And you can see all the values inside it.

Here is what the Inventory looks like.

What is cellNum and CellStatus? And their values

Firstly, I wouldn’t save the stats of the pet as value instances, since exploiters could easily modify them, and then have OP pets after loading into a new server because the pet saved with the modified values.
I would instead use a dictionary in a script that manages the pets. Something like this:

local pets = {
    [PetSpeciesHere] = {
        ["Damage"] = 4,
        ["Equipped"] = false,
        ["Name"] = "bob",
        ["Rarity"] = 2
    },
}

Then I would save each one (using a for key,value loop) into the datastore.
When loading these values back in, it’s a matter of creating a new key in the pets dictionary by doing

local petStats = [get the stats from the datastore here]

local pet = {}
for k,v in petStats do
    pet[k] = v
end

local pets[petStats[PetSpeciesHere]] = pet

I’m not that much familiar with datastores but that should give a rough idea of how it works.

Don’t mind that I tried to do something with those but it did not work out.

1 Like

I have a few things I would like to point out:

I’m not sure why you have three ‘templateScript’ scripts inside the frame, I’m not sure why they would be necessary, but I’m sure it would be better to have only one outside of the frame that handles every single pet.

All of the values: CellNum, CellStatus, DamageValue, EquippedValue, PetName and Rarity could be set as attributes instead of values, I haven’t fully looked into it but I’m positive that 6 values inside each pet can be pretty costly preformance-wise. Similarly, DamageValue, PetName and Rarity shouldn’t be there at all, it would definitely be better to have the damage, name and rarity of each pets in a module script in ReplicatedStorage, for example.

As for actually saving the pets, it’s really unreliable to have everything in the client. Nothing is stopping exploiters from duplicating the frames, and then they will have as many pets as they want. The best thing you can do is have a leaderstats folder created by the server inside the player instance, and then you can change, add and remove instances there from the server. The client scripts should only be for displaying the pets and handling inputs from the client, such as clicking a frame to equip it, whereas your server scripts should handle everything to do with data. Read here for some help on exploits, the client and the server.

However, if you do have all of your data in the server the way to go about it is to loop through all of your pets, add them to a table, then save the table. When the player joins again, get the pets from your datastore and add them all to the inventory.

-- Services
local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

-- Instances
local DataStore = DataStoreService:GetDataStore("DataStore#01")
local Remotes = ReplicatedStorage.Remotes
local SetupInventoryGui = Remotes.SetupInventoryGui

-- Loading data
local function Load(player)
    local PlayerData

    -- Gets the player's data inside a secure function
    local Success, Error = pcall(function()
        PlayerData = DataStore:GetAsync(player.UserId)
    end)

    -- Kicks the player if there was an error loading the data
    if not Success then
        player:Kick("Error loading data: " .. Error)
    end

    -- Creates a new folder for the player's pets
    local PetsFolder = Instance.new("Folder")
    PetsFolder.Name = "Pets"
    PetsFolder.Parent = player

    -- If the player has got data (not first time playing) then
    -- loop through all of their pets, creating a new value for it
    if PlayerData then
        for _, PetData in pairs(PlayerData) do
            local Pet = Instance.new("BoolValue")
            Pet.Name = PetData.Name
            Pet.Value = PetData.Equipped
            Pet.Parent = PetsFolder
        end
    end

    -- Tells the client to setup the inventory. Call this in the local script
    -- to setup the inventory
    SetupInventoryGui:FireClient(player)
end)

-- Saving Data
local function Save(player)
    local PetsFolder = player:FindFirstChild("Pets")
    if not PetsFolder then
        return -- The player hasn't created a pets folder, nothing will be saved
    end

    local PlayerData = {}

    -- Looping through all of the player's pets
    for _, Pet in pairs(PetsFolder:GetChildren()) do
        -- Add the pet's name and value to the data, then add it to the main table
        local Data = {
            Name = Pet.Name
            Equipped = Pet.Value
        }
        table.insert(PlayerData, Data)
    end

    -- Save the main table in a secure function
    pcall(function()
        DataStore:SetAsync(player.UserId, PlayerData)
    end)
end)

-- Detect player's joining & leaving
Players.PlayerAdded:Connect(Load)
for _, Player in pairs(Players:GetPlayers()) do
    Load(Player)
end
Players.PlayerRemoving:Connect(Save)

With a script similar to this in ServerScriptService, all you have to do is setup the inventory on the client through the remote event.

Best of luck to you, any issues let me know.

6 Likes

As @6Marchy4 said it needs to be saved on the server and with a folder in the player created by the server, but adding a point to that, other than just saving if it’s equipped or not you can save multiple things

local data = {
	"dog" = {
		Equipped = false,
		multiplier1 = 1.5, --etc
	},
}
1 Like

Ok, ty you very much, I will get working on it and I will notify you if any issues pop up.:slight_smile:

1 Like

Ok, it took a lot of hard work, but it finally works. TYSM you’re a legend :slight_smile:

Great job man! Best of luck for the rest of the game, hope you can get far! :slightly_smiling_face:

1 Like

You may not reply but if you don’t mind me asking can you explain why you turned the petdata into a boolvalue ?

Heya, I turned the PetData into a BoolValue because that’s all that’s necessary - the only keys inside PetData are ‘Name’ and ‘Equipped’. The Name in the PetData can be set to the name of the BoolValue, and the Value of the BoolValue will be whatever ‘Equipped’ is - true or false.

It’ll also be easier to change in the future, as you can call player.Pets[PetName].Value = false / true.

Hope this helps, let me know of any questions

Thank you i understand now i was a bit confused even tho i knew you cant save boolsvalues to a datastore.

You can’t, but you can save the value of the BoolValue to the datastore which is what you’d do in the saving function!