Is it possible to get the last valid Server transform on a client?

Hi!

I’ve got a situation where I’m animating some stuff using PositionConstraint as described in the Boss Room pick up action here:

One problem I’m running into with using this is that it’s possible for the client and server to become mildly out of sync doing this, and I’m struggling to find a good fix.

The exact situation is this:

I’ve got an async method that runs some ability (pickup, drop, throw, etc.) In this async method, I do client-only animation (no animations run on dedicated servers for perf reasons). During the client animation, I attach an object to a bone, do an animation, then detach the object from the bone in the async ability method. Sometimes, the ability is interrupted by the SERVER and cancellation of the async ability task on the CLIENT is triggered. For instance, if something hits the player while they’re picking something up, it forces them to drop it (which can happen when the client is doing the animation and awaiting ability validation from the server.)

After the client animation plays, the new position of the attached object will be X on the CLIENT. The server interrupted the ability, forces the player to drop the object, which is now at (authoritative) position Y on the SERVER.

So, my question is this:

Is there any good way to get the authoritative position Y on the CLIENT so the no-longer-attached object doesn’t appear at the now out-of-sync position X?

I looked for a way to mark the NetworkTransform (ClientNetworkTransform, in my case) as Dirty on the server but I couldn’t really see a way to do this directly.

My somewhat fragile fix for this is to teleport the object to a slightly different position on the server after an interrupt. It mostly works… mostly… but I’m expending extra logic finding a valid teleport spot, which I’d like to avoid.

Thoughts?

Thanks!

To interrupt this animation, I would assume the server sends a YouGotHitSoDropItClientRpc(). The server knows the object the client is about to pick up, so it can just pass the current authoritative position along with the RPC message. The client uses that to reposition the item that was in the process of being picked up.

Note that NetworkTransform has a “Teleport” method. I cannot remember the name exactly but it definitely has “teleport” in its name. If you call that, even with the exact same position the object is currently at, it will force the NetworkTransform to be synchronized.

1 Like

There’s actually no RPC sent, only replicated state. This is important for join in progress for other abilities to function correctly.

Teleport is exactly what I’m doing, and like I said it mostly works except when the teleport position is within the position threshold that gets checked in ApplyTransformToNetworkStateWithInfo().

My workaround is stupid, but it works. I teleport the object OUT of that threshold, then teleport it back to its original position. Which is a silly workaround to being able to force the transform to be dirty like you can with NetworkVariable.SetDirty().

Where this fails is when gameplay code acts on a transform change event, which I currently only have one minor thing (deriving Velocity on remote clients for walk animation speed. My networking situation is a bit weird lol)

Maybe this belongs in a feature request, because what I’m REALLY looking for is a NetworkTransform.SetDirty() method. I’ll post something in the GitHub and respond here I guess…

yeah, you shouldn’t be doing these hacks, lol. if you can open a feature request, that’d be great!

1 Like

Hacks are my middle name :sunglasses:

On a previous AAA project I worked we had a render call in a placement new operator to pass Cert.

This is nothin :wink:

I’ll open a feature request now and post back here in a bit…

1 Like

Feature Request opened here:

https://github.com/Unity-Technologies/com.unity.netcode.gameobjects/issues/2348

1 Like

Have you tried using NetworkTransform.SetState on the server-side with teleportDisabled = false?
This will force the owner client to set its transform and will force it to mark itself dirty. That will be updated back to the server, which it then gets propagated out to any other non-authoritative clients currently connected.

Interesting! I’ll give it a shot and see how it works out. I’m ankles deep in join-in-progress ability code today so might not get to it but appreciate the response!