How Can I Improve This Pet Saving System?

I’ve made a pet inventory system that saves the pet’s level and food amount. What can I do to make it run or/and look better?

local ds = game:GetService("DataStoreService"):GetDataStore("Backpack")
local backpack_folder = game.ServerStorage.Backpack--Define the backpack in ServerStorage
local pets_folder = game.ServerStorage.Backpack.Pets--Define the folder in ServerStorage with the pets
local ShowPet = game.ReplicatedStorage:WaitForChild("PurchasePrompts").ShowPet--Define the remote event that shows the pet in the playert's backpack

game.Players.PlayerAdded:Connect(function(plr)
	local Backpack = Instance.new("Folder")--Create a folder for their backpack
	Backpack.Name = "Backpack"
	Backpack.Parent = plr
	
	for _, v in pairs (backpack_folder:GetChildren()) do--Loop through all of the folders in the backpack
		
		local sub_folder = Instance.new("Folder")--Create a subFolder to be a child of the backpack (ex. Pets)
		sub_folder.Name = v.Name -- Name it the folder in ServerStorage
		sub_folder.Parent = Backpack

	end
	
	
	local petInventory = ds:GetAsync("PetInventory-"..plr.UserId)--get the player's pet inv data
	
	if petInventory then --If they have data
		for _, pet in pairs(petInventory) do--loop through all of the pets the player has
			if game.ServerStorage.Backpack.Pets:FindFirstChild(pet[1]) then--if the pet is a pet in ServerStorage
				
				local succ, msg = pcall(function()
					local petValue = Instance.new("Folder")--create a folder for the pet and put it in the player's backpack
					petValue.Name = pet[1]
					petValue.Parent = Backpack:FindFirstChild("Pets")
					
					local petLevel = pet[2]--get the pet's level and put it under the pet
					local AddPetLevel = Instance.new("IntValue")
					AddPetLevel.Name = "Level"
					AddPetLevel.Parent = petValue
					AddPetLevel.Value = petLevel
					
					local petFood = pet[3]--get the pet's food and put it under the pet
					local AddPetFood = Instance.new("IntValue")
					AddPetFood.Name = "Food"
					AddPetFood.Parent = petValue
					AddPetFood.Value = petFood
					
					ShowPet:FireClient(plr, pet[1])--fire the player so the pet shows up in their inventory
				end)
				
				if not succ then
					warn("Problem with getting and setting data ".. msg)
				end
			end
		end
	end
	
	
end)	


game.Players.PlayerRemoving:Connect(function(plr)
	
	local succ, msg = pcall(function()
		local petTable = {}--creates a table
	
		for i, pet in pairs(plr.Backpack.Pets:GetChildren()) do
				table.insert(petTable, {pet.Name, pet.Level.Value, pet.Food.Value})--insert pet table {pet's name, pet's level, pet's food}  ex. {"Ocean Egg", 6, 5}
		end
	
		ds:SetAsync("PetInventory-"..plr.UserId, petTable)--saving the table to the player
	end)
	

	if not succ then
		warn("Problem with saving data ".. msg)
	end
end)

Thanks!

1 Like

I’d say organize the code a bit, and maybe try and make a API Module which would have the pet systems like following, saving pet data and others for efficiency and maybe try and use a Data Saving API such as ProfileService or DataStore2 for example since they are more reliable than normal DataStore Service.

1 Like

About the pets_folder variable, just refer the backpack_folder instead of game.ServerStorage.Backpack.

1 Like

As covered in previous topics, the use of SetAsync is discouraged. I suggest changing it to UpdateAsync since it is just overall efficient and an easy alternative.

1 Like

In some cases this is true, but in reality “Data Saving APIs” are really just DataStores wrappers, about as reliable as the normal DataStoreService.

Not necessarily. UpdateAsync is just a wrapper for GetAsync & SetAsync, it should only be used if you just want code to look better (also better compilation?).
For example:

-- call GetAsync, then call the callback with the value
DataStore:UpdateAsync("m", function(data) 
    return "example" .. data -- call SetAsync with the returned key & value
end)

is the same as

DataStore:SetAsync("m", (function(data)
    return "example" .. data
end)(DataStore:GetAsync("m")))

and

local Data = DataStore:GetAsync("m")
DataStore:SetAsync("m", Data .. "example")

But for the sake of better looking code, go ahead and use UpdateAsync/DataStore2/ProfileService.

If there is a pet trading system, you could use ProfileService to prevent duping

1 Like

Hi Play,

I am using Profile Service for my pet system! Why? This has session locking, very easy to learn, and non-problematic. My PlayerData table is like this.


local ProfileTemplate = {
    Coins = 0,
    Clicks = 0,
    Pets = {
        PetsOwned = {},
        CurrentPets = {},
    },
}

function DataService:Get(player, DataWanted)
    local profile = Profiles[player]

    return profile.Data[DataWanted]
end

A remote function to retrieve data so client can see.

2 Likes