How to Sync in VRChat World Creation

*Note: [The original article](https://qiita.com/hatsuca_vr/items/63ee6ba04d2a785eed16) was written by [Hatsuka](https://twitter.com/hatsuca_vr), the creator of [VRC_PropHunt](https://twitter.com/hatsuca_vr/status/1011673069847343104).*


# Introduction

I would like to share my thoughts about sync problems that you can not avoid in VRChat world creation.


# 1. Basics

## BroadCastType and VRC_ObjectSync

First of all, I'll talk about the two most important things to know. VRChat doesn't synchronize anything without specific treatments except for player positions but synchronizes with either *BroadCastType* or *VRC_ObjectSync* in most cases.

When you set **other than Local** to VRC_Trigger *BroadCastType*, the action synchronizes to other players. The important thing here is that **only an action, which fulfilled its requirements, synchronizes**. It doesn't matter whether other player clients fulfilled or not.

**All the players in the same instance can see the same situation while they do the same actions**. That's how *BroadCastType* works. However, actions don't synchronize immediately because of latency. It would be messed up if there were other effects, such as gravity. Therefore, you need to use the *VRC_ObjectSync* component. It literally synchronizes objects in real time.

You might think it's useful. Okay, now I have a question for you.

"*BroadCastType* works with the player who fulfilled the requirements. Who is the player *VRC_ObjectSync* works with?"

The answer is **the player who has ownership**.

Ownership moves when **a player picks it up**, or **VRC client runs the TakeOwnerShip function**, etc. Spawn objects are owned by a player who runs the SpawnObject action.

You should know **who has ownership** if you want to synchronize objects that move with scripts.


# 2. How to Sync

## Sync by one player

As I noted, VRChat objects are synchronized by one player.  If a number of players engaged, it would be messed up because of latency. Basically, **only one player should engage**.

## Use Local

*Local BroadCastType* **doesn't do anything to other players**. You can make a specific player client do something while enabling a component or changing animator parameters in *Local*. You should prevent needless synchronizations taking advantage of *Local* since some VRC_Trigger requirements would be fulfilled by some players.

- All players, Always
  - OnPlayerJoined
  - OnPlayerLeft
  - OnSpawn
  - OnDestroy
- Some players, Not Always
  - Custom
  - OnEnable
  - OnTimer
  - OnEnterTrigger
  - OnExitTrigger
  - OnEnterCollider
  - OnExitCollider
  - OnAvatarHit

## Handle by master

It would be better that **only master client handles it** unless specific player has to do it. When *BroadCastType* is set as *Master*, master client does actions and sync while master client fulfills requirements. You can narrow it to master client with firing your custom trigger, which is set as *Master*, from ActivateCustomTrigger, which is set as *Always*.

## Sync visual only

It might be a problem with ownership if an object with *VRC_ObjectSync* had complicated structure. In that case, you should simplify synchronization. You shouldn't synchronize the object itself but synchronize other simple object which isn't related to the object and has *VRC_ObjectSync* and follows the object by *AutoCam* or *FollowTarget and LookatTarget*. The method is good for the problem of quaking while moving players with *VRC_Station*.


# 3. Examples

I uploaded my Unity package on GoogleDrive. Import it to your project and see the following sections.
https://drive.google.com/open?id=1GZQOVwo-q54RYOmzJqQ3yOwFLgNiInmF

## SyncDoor

It's a door that opens/closes by animation.

Changing animator parameters with *Always* is enough to synchronize simple animation, like the door has. I didn't use Toggle but used True/False on two objects.

![2018-06-27 (1).png](https://qiita-image-store.s3.amazonaws.com/0/266653/6aaa084b-6d5e-98c9-a75a-546608562dba.png)

Recently the sync method with *VRC_SyncAnimation* was established. It would be better to use it if there were various animations.

## TimerSystem

It's a simple count down timer.

When the timer starts, the custom trigger, which is named Timer, runs every second by the animation event on animator. If it ran in *Local*, it would get time difference because of each client processing speed.

At first, the timer runs in *Always*. Then it processes in *Master*. Only master client does it and it synchronizes every client.

![2018-06-27 (4).png](https://qiita-image-store.s3.amazonaws.com/0/266653/9473584a-acc3-8716-509b-0d18670b9b5e.png)

## ResetPositionGun

It's a gun that doesn't spawn bullets but recycles with *VRC_SceneResetPosition*.

You must notice the trigger actions *OnPickUp*. At first, a player who picks it up takes ownership. Second, it disables every player bullets' colliders and *FollowTarget* in *Always*. Third, it enables them in *Local*. That's how to separate the player who synchronizes and the other players who don't.

![2018-06-27 (5).png](https://qiita-image-store.s3.amazonaws.com/0/266653/b87a6f81-65ac-1e2e-c86f-2e86b2b5a706.png)

*FollowTarget* on the players who don't synchronize is disabled since it would overwrite the *VRC_ObjectSync* work. *FollowTarget* on the player who synchronizes is enabled in Local since it stores the bullets in the sky while not being used. When the player shoots, the *ResetPosition* function and the custom trigger which has the *AddForce* action run by animation event.


![2018-06-27 (6).png](https://qiita-image-store.s3.amazonaws.com/0/266653/d466567d-87eb-7b7d-42a3-c2bd6a9c627d.png)


# 4. Conclusion

There are a lot of sync methods out there. Since my method is just one of them, you have to find the most appropriate method for your world. When you find, could you share it for us?


VRChat 技術メモ帳
http://vrcworld.wiki.fc2.com/