How can I check a table's values for certain properties?

Not sure if the title made any sense, so I’ll raise you my situation.

I have a model with some parts in it. There’s a PrimaryPart defined as well. I made a script that tries to check if a part in the model is a PrimaryPart. If it is, it makes it the Part0 of the weld constraint. If it isn’t a PrimaryPart, it makes it Part1 of the weld constraint. The below script makes sense to me, but it says “invalid argument #3 (Instance expected, got number)”.

local model = script.Parent:GetChildren()
local PrimaryPart = script.Parent.PrimaryPart

for i,v in pairs(model) do
    if model[i]:isA('BasePart') then
	    local weld = Instance.new('WeldConstraint')
	
	    if model[i]:isA('PrimaryPart') then
		    weld.Part0 = i
		    weld.Parent = i
	    else
		    weld.Part1 = i       <<< (where the error occured)
	    end
    end
end

This is so simple, how did I not think of this? I’ve been racking my brain for 30 minutes…

Thank you!

You’re very close to correct code here, however there’s one maybe tricky detail you currently have wrong so I’ll attempt to explain it as best I can.

When constructing a for loop using pairs (or ipairs) you need to provide a table, as you have done. However, let’s stop to look at what the table you have provided is. You provided the table referenced by the variable model. The method GetChildren of the Model class returns a table which is, essentially, a list or array. This means that every element in the table can be indexed by its position in said list. What the variables created by a for loop using pairs or ipairs does is fill these variables on each iteration of the loop, the i variable corresponding to the “index”, and the v variable corresponding to the “value”. You do not need to name these variables i and v however, this is why the convention exists.

That being said, you don’t need to re-access the model in order to get a reference to each part as you do in the line:

if model[i]:isA('BasePart') then

Instead, v already references a particular Part in the model and on each iteration, will reference a different Part. You get the error “invalid argument #3 (Instance expected, got number)”, because with the table you are currently providing (a list, instead of a dictionary table), i will always be a number. You can fix your code (at least in the sense it will run) like this:

local model = script.Parent:GetChildren()
local PrimaryPart = script.Parent.PrimaryPart

for i,v in pairs(model) do
   if v:IsA("BasePart") then
      local weld = Instance.new('WeldConstraint')
      
      if v == PrimaryPart then --We can just compare the two instances to see if they are the same object
         weld.Part0 = v
         weld.Parent = v
      else
         weld.Part1 = v
      end
   end
end

This code should run fine, however it appears you’re attempting to essentially weld the entire model so that all parts stay in relative location to the PrimaryPart. In order for this to be the behavior of the code, you need to address the issue that you are not setting the Part0 properties of any of the WeldConstraints except the one created for the PrimaryPart (which is actually an unesserary WeldConstraint). Here is code that would create a WeldConstraint for all the direct BasePart children of a model (except the PrimaryPart), and correctly set the Part0 and Part1 properties:

local partList = script.Parent:GetChildren()
local primaryPart = script.Parent.PrimaryPart

for i,v in pairs(partList) do
   if v:IsA("BasePart") then
      if v ~= primaryPart then --We do not want to create a weld for the PrimaryPart
         local weld = Instance.new("WeldConstraint")
         weld.Parent = primaryPart --Put all the welds in the PrimaryPart. Or this could be changed to another location
         weld.Part0 = primaryPart --We want all other parts to be welded in relation to the PrimaryPart
         weld.Part1 = v
      end
   end
end

3 Likes