Animation not syncing of client player when your current tab is not focused

Hi there,

I was connected in a multiplayer session in a room. My player A is looking at player B who is sitting on a chair whose current animation is ā€˜sitDown’. When I switch to some other browser tab and player B moved away from the chair and standing idle now in space. Now when I come back to my current tab and I see that player B is at new position where he was standing idle but I see player B animation as ā€˜SitDown’ only.

Its updates for me only when player B move again after I came back to my current screen.

I saw the logs from ā€˜debuganimatorcontroller’, I found that I didn’t received the log ā€˜transition changed to 0(idle)’ only got the log Set Trigger to ā€˜idle’.

Original Post on Discord

by user 389863047159873540

Hey, are you using SyncedAnimator or something different to sync the state?
Do you see the same issue on Synchronized Animator | Needle Engine ?

I’ve used ā€˜connection.send’ and client gets update from ā€˜beginListen’ callback. Please find the code snippet for logic I’ve used for my custom SyncedAnimator. Let me know if there is any issue in it. If this didnt work, I will used the sample logic of SyncedAnimator.

onEnable(): void {
        this.animator = this.gameObject.getComponent(Animator) as Animator;
        this.context.connection.beginListen("animCall", this.onAnimationUpdated);
    }

    onDisable(): void {
        this.context.connection.stopListen("animCall", this.onAnimationUpdated);
    }

    onAnimationUpdated = (response: AnimModel) => {
        if (!this.animator) return;

        if (response.id === this.syncedTransformGuid) {
            this.ResetAllTriggers();
            this.animator.setTrigger(response.transitionTo);
        }
    }

    public SetTrigger(transitionTo: string) {
        if (!this.animator) return;

        this.ResetAllTriggers();
        this.animator.setTrigger(transitionTo);
        this.animModel = new AnimModel(this.syncedTransformGuid, transitionTo);
        this.context.connection.send("animCall", this.animModel);
    }

    private ResetAllTriggers() {
        if (!this.animator) return;

        this.animator.resetTrigger("idle");
        this.animator.resetTrigger("walking");
        this.animator.resetTrigger("running");        
        this.animator.resetTrigger("dance");
        this.animator.resetTrigger("sitDown");
        this.animator.resetTrigger("sitIdle");
        this.animator.resetTrigger("standUp");
    }

by user 389863047159873540

Does your AnimModel have a guid?

If it hasn’t it will not be persisted, which means it’s a one-off event and won’t be rolled into state updates that you get later.

@Marcel_Wiessler1 :cactus: please correct me if I’m wrong on that

Can you show your AnimModel ? It needs a guid to be stored in the state, yes

So I created a class like this:

class AnimModel {
    id: string;
    transitionTo: string;

    constructor(id: string, transitionTo: string) {
        this.id = id;
        this.transitionTo = transitionTo;
    }
}

Should I add one more string field as guid: string in AnimModel and send call be like this:

this.animModel = new AnimModel(this.syncedTransformGuid, transitionTo, this.guid);
this.context.connection.send("animCall", this.animModel);

I tried this but didn’t work.

by user 389863047159873540

this.syncedTransformGuid I’m getting this from another class where I’m downloading model and assigning SyncTransform at runtime. So its like that

// my Character loading class...
:
:
@serializable(SyncedTransform)
currentSyncedTransform!: SyncedTransform;
:
:
async downloadAndApply(url: string) {
:
// downloading model from url and instantiating it as a GameObject
:
:
//
let syncAnimatorInstance = GameObject.addNewComponent(go, SyncAnimator);

if (syncAnimatorInstance) {
  syncAnimatorInstance.awake();
  syncAnimatorInstance.enabled = true;

  if (this.currentSyncedTransform) {
    syncAnimatorInstance.syncedTransformGuid = this.currentSyncedTransform.guid;
  }
}
:
:

by user 389863047159873540

do not use the same guid for your animation and position.
The guid is an ID for the storage on the server, so under a single guid a single message is stored. And the usecase here is to store the last message for whoever connects to get it.

This way you could be randomly ā€œloosing dataā€, since it is sharing a single ID for 2 unique information.

While it is called guid, it is rather just a unique string. So to make it deterministic i would advice to add a prefix and set that to the sync animator.

like… anim_${syncTransform.guid} and see if that solves the issue of loosing state on ā€œreconnectā€.

Thanks Kipash. I got your point. Will try the way you suggested. :+1: :grinning:

by user 389863047159873540

BTW, if you have any feedback in regards to the networking API and usage, feel free to share :cactus: