Model:PivotTo() moves non-descendant Anchored Parts

Reproduction Steps
PivotToTest.rbxl (32.8 KB)

In the attached place, there is a Script in workspace named “PivotModel” that pivots workspace.Model. There is also an anchored part called “AnchoredPart” in workspace. The AnchoredPart incorrectly gets moved by the pivot call because it is welded to the Model which is being pivoted.

  1. Simulate (run) the place (no character necessary)
  2. Notice that the script in workspace is moving the workspace.AnchoredPart despite only attempting to move the workspace.Model

Expected Behavior
According to the documentation, PVInstance:PivotTo(cframe) should only transform a specified instance and its descendants. I expect only the model which I call PivotTo() on to move, and any external objects welded to the model should remain in place.

Actual Behavior
Currently, there is an issue where if a Model contains a part that is attached (with a Weld) to another part outside of the model, then other part outside of the Model is also moved when PivotTo is called on the Model.

In the demo, the part named AnchoredPart under workspace is moved, despite not being a descendant of the Model on which PivotTo is called.

Issue Area: Engine
Issue Type: Other
Impact: High
Frequency: Constantly
Date First Experienced: 2022-01-05 00:01:00 (-05:00)
Date Last Experienced: 2022-01-07 00:01:00 (-05:00)

It also seems the case that setting an unanchored part’s CFrame directly will also move anchored parts that are welded to the part, but an anchored part being moved will not cause connected parts to move.

Yes, but since you welded the Part to the Model it is now a descendant of the Model.
WeldConstraint | Roblox Creator Documentation states that “In contrast, if a part’s CFrame is updated, that part will move and any part welded to that part will also move. These other parts will be moved to make sure they maintain the same offset as when the weld was created”.

1 Like

It might be confusing to call it a descendant since a welded part won’t necessarily show up if the GetDescendants() method is called on the first model. I agree that it is the weld documentation rather than that of the PivotTo that is key here. The welds don’t follow if an object is moved using its Position property, but they do follow if the object is moved using its CFrame.

PivotTo() uses the CFrame. Seems like the expected behavior to me.

1 Like

Yeah sorry, it isn’t really a descendant, but as you said, it’s now attached to the model.

I agree, so the issue may be that the PivotTo docs are inaccurate as they say only descendants will be moved, not connected parts.

I didn’t realize setting CFrame behaved this way, but I have also found that it only moves the welded parts if the moved part is unanchored, not if it is also anchored, which would be a bug then?

PivotTo explicitly states that descendants will move, but it doesn’t seem to be worded in a way that would preclude other things like welded parts from moving as well. I might be missing where it says “only”. If it’s there then, yeah, that would seem inaccurate. Something for Bug Reports → Developer Hub Issues.

The unanchored thing could be a bug. It also seems like reasonable behavior. Should a welded part follow another if it’s been anchored? Seems like there are several ways that situation could be handled, but if it’s covered in the docs, I can’t find it. Maybe another candidate for Dev Hub Issues. I’d like to see what it’s supposed to do before calling that one a bug in this category.

1 Like

That makes sense for PivotTo, but the issue with the anchoring inconsistency is that it is the anchored status of the CFramed part that determines whether other parts follow it or not. Considering the docs say that any time a part’s CFrame is set that welded parts will also move, they should always move or the docs are inaccurate.

I can get the documentation updated but this is not a bug.

Joints trump basically anything else in the engine. If you move A in any way, and there’s an active joint between A and B, you should assume that B will always move as well. Where by “active joint” we mean a non-redundant joint between two parts where at least one of the parts isn’t Anchored.

Consider the alternative:

  • First, I think we can agree that calling PivotTo should definitely not break any joints

  • Now imagine that we PivotTo the model, and the Anchored part doesn’t move

  • Well, the other part will immediately snap right back where it came from thanks to the weld

Basically, the alternative is that the part you’re calling PivotTo on doesn’t move at all. The resolution to this is that if you really want to be sure you’re moving only the model and not anything attached to it, you should call BreakJoints on it first, or use GetJoints() to walk and destroy and external joints if you need to preserve the internal ones.

3 Likes

Thanks, this was helpful. The one additional issue I had relating to this was that if you are seated (character welded to Seat) and you destroy the weld and set the character’s cframe on the server, the character will immediately snap back to the seat, I’m assuming because the Seat weld destruction replicates after the character movement. Is the workaround here to wait for replication then signal the server before teleporting the character?

That probably has to do with network ownership and might actually be a bug.

The player’s client likely owns physics simulation for the car while you’re seated in it, so there’s some awkwardness in the physics ownership handoff that happens when you hit the engine with both the CFrame change and breaking of the joint at the same time with replications of the position changes that were computed on the client still coming in.

It sounds weird but can you try setting both the CFrame of the car and the CFrame of the player on the server after breaking the joint? I believe that might actually fix it.

1 Like

No car or networked physics involved, in my case I am seated on an anchored Seat with no movement (anchored parts have no owner, I think). This is why I suspected it was just an issue of replication priority, where character position replication is prioritized over joint changes (when joint changes should sometimes be processed first if they relate to the character)

When I set the CFrames of both the Seat and the Character on the server to both be the same far point, the character will still snap back to the old position where there is no longer anything.

Here is what I suspect is happening:

  1. [Server] Destroy weld
  2. [Server] Pivot character far away
  3. [Client] Receives character CFrame update, still has the weld, and snaps back to satisfy the weld.
  4. [Client] Receives weld removal replication packet, character can now be moved without snapping back

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.