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.