I’ve been trying to find a way to make my pet system save. After finding out that you could only save values on Roblox I realized this would be so easy and still attempted it. I attempted to make the values in my UnlockedPets folder(towards the bottom) save however it doesnt work and I need some guidance. This is also how my folders are setup for reference.
local DataStoreService = game:GetService("DataStoreService")
local playerData = DataStoreService:GetDataStore("PlayerData")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local MarketplaceService = game:GetService("MarketplaceService")
local ServerScriptService = game:GetService("ServerScriptService")
local HTTPService = game:GetService("HttpService")
local function InstanceObject(class, parent, name, value)
local object = Instance.new(class, parent)
object.Name = name
if value then object.Value = value end
return object
end
local function onPlayerJoin(player)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
local coins = Instance.new("IntValue")
coins.Name = "Coins"
coins.Parent = leaderstats
local gems = Instance.new("IntValue")
gems.Name = "Gems"
gems.Parent = leaderstats
local slimed = Instance.new("IntValue")
slimed.Name = "Slimed"
slimed.Parent = leaderstats
local backpackMax = Instance.new("IntValue")
backpackMax.Name = "BackpackMax"
backpackMax.Parent = player
local Management = InstanceObject("Folder", player, "Management", nil)
local MaxPets = InstanceObject("IntValue", Management, "MaxPets", 20)
local UnlockedPets = InstanceObject("Folder", Management, "UnlockedPets", nil)
local Inventory = InstanceObject("Folder", player, "Inventory", nil)
local Pets = InstanceObject("Folder", Inventory, "Pets", nil)
local character = player.Character or player.CharacterAdded:Wait()
repeat wait() until character:FindFirstChild("HumanoidRootPart")
repeat wait() until character:FindFirstChild("Head")
repeat wait() until character:FindFirstChild("Humanoid")
local EquippedPets = InstanceObject("Folder", character, "EquippedPets", nil)
local playerUserId = 'Player_'..player.UserId
local data = playerData:GetAsync(playerUserId)
if data then
coins.Value = data["Coins"]
gems.Value = data["Gems"]
slimed.Value = data["Slimed"]
backpackMax.Value = data["BackpackMax"]
else
coins.Value = 10000
gems.Value = 0
slimed.Value = 0
backpackMax.Value = 10
end
local at = require(ReplicatedStorage.Modules.Handlers.TableOfAssets)
local owns_extra_max_pets = MarketplaceService:UserOwnsGamePassAsync(player.UserId, at.gamepasses["Extra Max Equipped Pets"].id)
print(owns_extra_max_pets)
local MaxEquipped = InstanceObject("IntValue", Management, "MaxEquippedPets", owns_extra_max_pets and at.game_settings.extra_max_equipped_pets or at.game_settings.max_equipped_pets)
end
local function create_table(player)
local player_stats = {}
for _, stat in pairs(player.leaderstats:GetChildren()) do
player_stats[stat.Name] = stat.Value
end
return player_stats
end
local function create_table2(player)
local unlocked_pets = {}
for _, unlockedP in pairs(player.Management.UnlockedPets:GetChildren()) do
unlocked_pets[unlockedP.Name] = unlocked_pets.Value
end
return unlocked_pets
end
local function onPlayerExit(player)
local player_stats = create_table(player)
local unlocked_pets = create_table2(player)
local success, err = pcall(function()
local playerUserId = 'Player_'..player.UserId
playerData:SetAsync(playerUserId, player_stats)
playerData:SetAsync(playerUserId, unlocked_pets)
end)
if not success then
warn("Could not save data")
end
end
game.Players.PlayerAdded:Connect(onPlayerJoin)
game.Players.PlayerRemoving:Connect(onPlayerExit)
Where are all of the other pets stored? (Includes locked pets)
Either way, I think the easiest way to do it (as you already attempted) is to make a table of the pets’ names. You would then SetAsync with that table, then find the pet in the overall pets’ folder based on the name.
Also, I would highly not recommend not using SetAsync twice (as you did in the end). This not only overwrites data and only saves the unlocked pets, but could fill up the datastore queue. Instead, you would either make one table for both the player stats, or two separate datastores for the player stats and unlocked pets.
--for saving both unlocked pets and player stats in one table.
--The player stats are the first value of the table, and the unlocked pets are the second value
local DataStoreService = game:GetService("DataStoreService")
local playerData = DataStoreService:GetDataStore("PlayerData")
local pets_folder = game.ReplicatedStorage.Pets --change this to match pets folder
game.Players.PlayerAdded:Connect(function(plr)
local getData = playerData:GetAsync(plr.UserId(
if getData ~= nil then
local stats, pets = getData[1], getData[2]
for name, val in pairs(stats) do
plr.leaderstats[name].Value = val
end
for _, name in pairs(pets) do
pets_folder[name]:Clone().Parent = plr.Inventory.Pets
end
else
--load respected leaderstat values if no data exists
end
end)
game.Players.PlayerRemoving:Connect(function(plr)
local stats, pets = {}, {}
for _, s in pairs(plr.leaderstats:GetChildren()) do
stats[s.Name] = s.Value
end
for _, p in pairs(plr.Inventory.Pets:GetChildren()) do
table.insert(pets, p.Name)
end
playerData:SetAsync(plr.UserId, {stats, pets})
end)
Try this sample code I typed out. Try to implement it with your current code, and see if it works. Let me know if you have any issues or questions.
Thanks for the assistance. I tried implementing the code and I ran into an error so im not sure if im doing it correctly here’s what I have
local DataStoreService = game:GetService("DataStoreService")
local playerData = DataStoreService:GetDataStore("PlayerData")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local MarketplaceService = game:GetService("MarketplaceService")
local ServerScriptService = game:GetService("ServerScriptService")
local HTTPService = game:GetService("HttpService")
local pets_folder = ReplicatedStorage:WaitForChild("ReplicatedPets")
local function InstanceObject(class, parent, name, value)
local object = Instance.new(class, parent)
object.Name = name
if value then object.Value = value end
return object
end
local function onPlayerJoin(player)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
local coins = Instance.new("IntValue")
coins.Name = "Coins"
coins.Parent = leaderstats
local gems = Instance.new("IntValue")
gems.Name = "Gems"
gems.Parent = leaderstats
local slimed = Instance.new("IntValue")
slimed.Name = "Slimed"
slimed.Parent = leaderstats
local backpackMax = Instance.new("IntValue")
backpackMax.Name = "BackpackMax"
backpackMax.Parent = player
local Management = InstanceObject("Folder", player, "Management", nil)
local MaxPets = InstanceObject("IntValue", Management, "MaxPets", 20)
local UnlockedPets = InstanceObject("Folder", Management, "UnlockedPets", nil)
local Inventory = InstanceObject("Folder", player, "Inventory", nil)
local Pets = InstanceObject("Folder", Inventory, "Pets", nil)
local character = player.Character or player.CharacterAdded:Wait()
repeat wait() until character:FindFirstChild("HumanoidRootPart")
repeat wait() until character:FindFirstChild("Head")
repeat wait() until character:FindFirstChild("Humanoid")
local EquippedPets = InstanceObject("Folder", character, "EquippedPets", nil)
--line with the error
local getData = playerData:GetAsync(player.UserId())
if getData ~= nil then
local stats, pets = getData[1], getData[2]
for name, val in pairs(stats) do
player.leaderstats[name].Value = val
end
for _, name in pairs(pets) do
pets_folder[name]:Clone().Parent = player.Inventory.Pets
end
else
--load values if there is none
coins.Value = 10000
gems.Value = 0
slimed.Value = 0
backpackMax.Value = 10
end
-- this im not trying to save
local at = require(ReplicatedStorage.Modules.Handlers.TableOfAssets)
local owns_extra_max_pets = MarketplaceService:UserOwnsGamePassAsync(player.UserId, at.gamepasses["Extra Max Equipped Pets"].id)
print(owns_extra_max_pets)
local MaxEquipped = InstanceObject("IntValue", Management, "MaxEquippedPets", owns_extra_max_pets and at.game_settings.extra_max_equipped_pets or at.game_settings.max_equipped_pets)
end
local function onPlayerExit(player)
local stats, pets = {}, {}
local success, err = pcall(function()
for _, s in pairs(player.leaderstats:GetChildren()) do
stats[s.Name] = s.Value
end
for _, p in pairs(player.Inventory.Pets:GetChildren()) do
table.insert(pets, p.Name)
end
playerData:SetAsync(player.UserId, {stats, pets})
end)
if not success then
warn("Could not save data")
end
end
game.Players.PlayerAdded:Connect(onPlayerJoin)
game.Players.PlayerRemoving:Connect(onPlayerExit)
i was moving some stuff around and i think the problem is that well inside the pets I have two values for the pets tier and an object value so when it saves it doesnt save the 2 values in the pet which breaks the whole inventory. Do you know how i could save those also
It’s a data structures problem. Can people have more than one of the same pet type? If not then you could perhaps use the key to name dictionary/table and store values in a dictionary/table.
Or otherwise if multiple can be owned, you could move the key inside the dictionary/table and stor them as a array/table. e.g.
{
{petType = “pet_name_1”, value1 = true, value2 = “hello”},
{petType = "pet_name_2 ", value1 = true, value2 = “hello”, value4 = 30},
…
}
I’m working on a similar project and I found it viable to just store the type of pet as a dictionary (players can own multiple pets of the same type) and then store their attributes such as rarity, level, etc in a table within said dictionary.