I’m trying to make a pet-saving simulator-style inventory system. Previously, spawning in a pet from an egg would just make it spawn at world-spawn and fly over, which it still does, in theory. I hooked up a print function to it and it fired hundreds of times for some reason. It crashes my Studio when testing in single-player, and I’m very confused about what’s going wrong. The printing line is line 32, printing “Pet”, to signal when a new pet has been added to a player’s inventory. Here’s the script with detection:
local function getXAndZPositions(angle)
local x = math.cos(angle) * 10
local z = math.sin(angle) * 10
return x, z
end
game:GetService("RunService").Heartbeat:Connect(function()
for i,v in pairs(game.Players:GetPlayers()) do
local petTable = {}
for e,d in pairs(workspace:GetChildren()) do
if d:GetAttribute("Pet") == true then
if d.Owner.Value == v then
petTable[#petTable+1] = d
end
end
end
for e,d in pairs(petTable) do
local angle = e * (math.pi * 2 / #petTable)
local x, z = getXAndZPositions(angle)
local position = (v.Character.PrimaryPart.CFrame * CFrame.new(x + v.Character.Humanoid.MoveDirection.X, 0, z + v.Character.Humanoid.MoveDirection.Z)).p
local lookAt = v.Character.PrimaryPart.Position
d.BodyGyro.CFrame = CFrame.new(position, lookAt)
d.BodyPosition.Position = position
local petModule = require(game.ServerStorage.PetModule)
if #v.Inventory:GetChildren() > 0 then
for q,w in pairs(v.Inventory:GetChildren()) do
if w.Name ~= d.Name then
print("Pet")
local folder = Instance.new("Folder", v.Inventory)
folder.Name = w.Name
local clickM = Instance.new("IntValue", folder)
clickM.Name = "Click"
for f,g in pairs(petModule) do
if g[1] == w.Name then
clickM.Value = g[3][1]
end
end
end
end
else
local folder = Instance.new("Folder", v.Inventory)
folder.Name = d.Name
local clickM = Instance.new("IntValue", folder)
for f,g in pairs(petModule) do
if g[1] == d.Name then
clickM.Value = g[3][1]
end
end
end
end
end
end)
Two comments before I get to what I think is causing the issue:
- Please use more descriptive names than “e,d” and “q,w” when looping through tables. I.e. “pet” for d in the second loop.
- You are connecting to heartbeat, which is running dozens of times per second. Is this necessary? You could just connect to your opening egg event and add it to the inventory and have it move then. Also, you are also looping through every child of workspace. Not sure how large your game is, but that’s a performance hit if I’ve seen one. Try looping through a “Pets” folder under workspace or something, one that you store all the pet models in.
Main issue:
To my understanding, you loop through all of the pets in workspace several times a second. For each pet that you find with the player as its owner, you print “Pet”. Do you ever remove the pet? Change its owner? Move it to a section where it will not be looped through? I do not believe so, at least from the code that I’ve seen. So basically, this pet that you just printed for will trigger another print line for every time you run this code (dozens of times per second or more).
Basically, you do nothing to prevent the same pet from triggering the function again.
Possible solutions:
Put the pets in a “AddedToInventory” folder when you add them to the inventory. Don’t loop through the added to inventory folder when checking in your update function.
Instead of running many times per second, which is unnecessary, try connecting to an event or firing a bindable event after opening the egg (if you need a link to the reference page just ask).
Not-necessary, but highly recommended extras:
Don’t loop through workspace, loop through a folder instead.
Change index, value variable names to more descriptive ones for legibility.
Hope this helps!
2 Likes
Alright, thanks! I’ll try those.
Correct me if I’m wrong here but this shouldn’t work.
local petTable = {}
for e,d in pairs(workspace:GetChildren()) do
if d:GetAttribute("Pet") == true then
if d.Owner.Value == v then
petTable[#petTable+1] = d -- #petTable always will return 0
end
end
end
From my experience, # table only returns the actual number when you use table.insert to add the item. This loop just sets petTable[1] to d
I don’t believe this is correct. #table
simply returns the length of the table. In fact, table.insert also uses the length operator #
. Lua 5.1 Reference Manual
The method of table[#table+1] = Something
works perfectly fine, and even faster than table.insert.
(lua - What's the difference between table.insert(t, i) and t[#t+1] = i? - Stack Overflow)
It seems I misjudged. I guess it works if the indexes are in order. But this never panned out for me:
local tabl={} tabl[1]=3 tabl[3]=5 tabl[6]=7
print("number:",#tabl) -- prints '1' even though there are clearly 3 numbers in the table
local n=0
for i,v in pairs(tabl) do
n+=1
end
print("number:",n) -- i have to resort to this for certain tables, like tables I have with a character as an index and a value indicating the damage they took
clueless as to why. My suspicion is the # function works like this
local num=0
while true do
num+=1
if not tabl[num] then num-=1 break end
end
return num
Correct, they have to be in order:
“The length of a table t
is defined to be any integer index n
such that t[n]
is not nil and t[n+1]
is nil ; moreover, if t[1]
is nil , n
can be zero. For a regular array, with non-nil values from 1 to a given n
, its length is exactly that n
, the index of its last value. If the array has “holes” (that is, nil values between other non-nil values), then #t
can be any of the indices that directly precedes a nil value (that is, it may consider any such nil value as the end of the array).” (Lua 5.1 Reference Manual)
In your example, a value with an index of 1 exists while a value with an index of 2 does not. Not sure why you do it like this nor need the exact length of the table after iterating through it. In instances where you do not have a numerically increasing table with only integer keys, you have to iterate over the table using pairs() or ipairs() anyways. I tend to store important information in cases like this in both a string key (not integer) and the value, which can be helpful.
Basically, as soon as your table is no longer an array with only sequential integer indexes, you have to iterate over it using pairs() and ipairs(). I would suggest switching to a different format, either to string or more useful keys than integers, or finding a way to only use sequential indexes.