Connect a function to Part:GetPropertyChangedSignal(“AssemblyRootPart”) and use a WeldConstraint to weld that part to other parts to change the root part
This is a bit unfortunate but is the intended behavior for performance reasons.
Allowing the physics engine to freely reshuffle the spanning tree (the thing the part is an assembly root of) whenever it wants and not have to go back and contact the DataModel about the changes provides a large performance benefit. Basically, it’s similar to the reasoning for you not getting CFrame changed events when parts are being moved thanks to physics simulation.
If you want a predictable root for game logic purposes you should make use of the RootPriority property to get that.
Would it be possible to make it so the Changed event fires just before the Stepped event, after all physics have been finished? So if during the physics step the solver needs to change the assembly root 20 times it can still do that, but only fire the Changed signal for the last time it changes before the Stepped event fires.
My use case is for custom gravity. I have planetary physics in my game so workspace.Gravity = 0. Right now I have to poll thru hundreds or thousands of parts every frame to check if that assembly root has been updated that frame. Vehicles can be broken apart by explosions and hopefully soon RigidConstraints
If the changed event fires before the Stepped event, I could connect to that and make sure all the assembly roots have their gravity updated without having to poll thousands of parts
There is an approach for you to take here: Handle things on the DataModel side to begin with. You can listen on joints being formed / destroyed and that will give you a more precise instrument to handle things anyways, because the root part is changing on tons of stuff all the time as joints are formed / destroyed even if nothing needs to change about them, vs looking at a joint being formed / destroyed gives you exactly two objects to look at.
For maximum efficiency you could augment the places in your code that form / destroy joints with a hook that your gravity adjustment code can tap into.