Undefined GetMass behavior on hat handles

I’m calling part:GetMass() on descendants of the character when DescendantAdded fires. When it is called on the Handle part in an Accessory, it returns a positive number. Some arbitrary amount of time later (around .15 seconds), the mass becomes 0, seemingly without any detectable indication that it did. Now the mass calculations that already finished are wrong because the mass silently changed.

reproduction (LocalScript in StarterCharacterScripts):

script.Parent.DescendantAdded:Connect(function(part)
	if part:IsA("BasePart") and part.Parent:IsA("Accoutrement") then
		local path = part:GetFullName()
		print(path, part:GetMass())
		part.Changed:Connect(function(property)
			print("(changed)", part:GetFullName(), property, part[property], part:GetMass())
		end)
		wait(1)
		print("(new mass)", path, part:GetMass())
	end
end)

example output:

  Workspace.1waffle1.Angel.Handle 25.199998855591
  (changed) Workspace.1waffle1.Angel.Handle Parent Angel 25.199998855591
  Workspace.1waffle1.DominusV2.Handle 5.5999999046326
  (changed) Workspace.1waffle1.DominusV2.Handle Parent DominusV2 5.5999999046326
  Workspace.1waffle1.AncalagonGreenBlack.Handle 11.648006439209
  (changed) Workspace.1waffle1.AncalagonGreenBlack.Handle Parent AncalagonGreenBlack 11.648006439209
  (new mass) Workspace.1waffle1.Angel.Handle 0
  (new mass) Workspace.1waffle1.DominusV2.Handle 0
  (new mass) Workspace.1waffle1.AncalagonGreenBlack.Handle 0

I included the connection to Changed to show that there’s no indication that the mass changes.
The output here seems to also demonstrate another bug: Changed fires because the Parent changed, but it didn’t.

This is likely due to the Massless property. Is part.Massless true before you wait a second? Maybe the engine inserts the hat, then sets the Massless property to true. Hats would ideally be fully initialized before they’re inserted into the DataModel.

GetMass doesn’t seem to respect Massless, so if it is because of that it would be unique behavior.

Massless is actually never set to true. If it were then the Changed event should have caught it, but it seems to use some other internal mechanic to negate its mass.

It seems that GetMass will return 0 if Massless is true, but only if the part is connected to something that does not have Massless set to true. Which makes sense; applying a force to something massless would propel it at infinite speed, so ignoring it unless it’s attached to something with mass is okay. Hats are attached to the characters, but Massless isn’t true, it just behaves like it is.

This might be because hats became massless before the Massless property was introduced:
https://devforum.roblox.com/t/massless-hats-other-accoutrement/38961 (June 2017)
https://devforum.roblox.com/t/new-basepart-properties-massless-rootpriority/208661 (December 2018)

1 Like

Accoutrements are implicitly massless.

Massless in general has no effect unless it is welded to another part and it is not the root part of the welded assembly because we can’t have moving bodies with zero mass. Looks like your script would execute before all descendants of the character are added to the Workspace.

If this script runs before all parts and accessory welds are added, you’ll get the wrong mass value.

If this is a player character try waiting for CharacterAdded, which should now be fired after the character is in Workspace.

If not, at least add a listener for AncestryChanged on the root character Model and wait until after the model is parented to the workspace. If you’re trying to handle accessories added after the fact you’ll need to wait for the weld to be added before you recompute mass.

An easy solution might be to have DescendantAdded just set a dirty flag and recalculating later in the frame if this is set.

1 Like