So, unfortunately for now this is a difficult case to resolve.
The Roblox replication system assumes that all property changes are independent from each other, when sending them over the network, so that they can be re-shuffled for optimal perf/bandwidth use.
This assumption is broken with certain physics/position properties like “AssemblyAngularVelocity”, because the side-effects of this property being called depends on the state of your assemblies. When you set that property AND break a weld, if those changes are delivered in the same frame, they may get shuffled such that the velocity is applied on the “wrong” assembly state.
For example if on server you have [ Part A ]--weld--[ Part B ]
and you call
PartA.AssemblyAngularVelocity = X
weld:Destroy()
PartA.AssemblyAngularVelocity = Y
On the server you would see PartB
having angular velocity X
while PartA
having angular velocity Y
… but the Client MAY (not guaranteed) apply angular velocity Y
on both PartA
and PartB
, because when it gets applied it still thinks both objects are the same assembly.
This is because the Replication system sees the first call to PartA.AssemblyAngularVelocity = X
as redundant and simply replaces it with PartA.AssemblyAngularVelocity = Y
in place, which causes the Client to receive an update that looks like this:
PartA.AssemblyAngularVelocity = Y
weld:Destroy()
We’re working on a long-term project to clean up some of these replication caveats, but it would be very difficult to fix this in the short term, so I won’t have a solution for you in the short term for a while.
If I understand your problem correctly:
A possible workaround for your issue you can use RemoteEvent
or RemoteFunction
to force these changes to happen atomically.
So when you do the initial set of calls, a remote event first
setVelocitiesBreakWeld:FireClients()
PartA.AssemblyAngularVelocity = X
weld:Destroy()
PartA.AssemblyAngularVelocity = Y
and on the Clients basically make sure your remote event function does the exact set of operations you need in the right order.
setVelocitiesBreakWeld.OnClientEvent:connect(function()
PartA.AssemblyAngularVelocity = X
weld:Destroy()
PartA.AssemblyAngularVelocity = Y
end)
This might do redundant work, but it will force everything into the right state “atomically”.
Alternatively, waiting a frame between
PartA.AssemblyAngularVelocity = X
weld:Destroy()
and
PartA.AssemblyAngularVelocity = Y
should make this less likely to happen but doesn’t guarantee it during congested network situations.
Does that make sense? And did I describe the issue correctly? Let me know if I misunderstood something.