在你正式开始网络同步之前——你最好知道的一些事 本文是我 【ARK-Magellan】 在学习网络同步开发过程中,对遇到的各类问题及解决方案的整理记录。内容整合了日本及其他技术网站的知识,虽非原创但经过系统性梳理——这些知识点在网络同步开发中至关重要,希望你能认真阅读,并在实际开发中遵守相关核心原则。 一切的开始 你必须要保证你已经会写本地的逻辑了再来考虑学习网络同步——但是在你从创建脚本开始,就应该考虑号网络同步的问题。 因为将一个网络同步变成本地脚本,只需要将同步状态改为 None ,但是把一个本地脚本变成网络同步脚本,无异于重新写一遍…… 很好你已经准备好了 你需要知道的是 网络同步本身是一个复杂且易出问题的系统: Manual 同步的 OnDeserialization() 发生时不一定所有的变量已经完成了同步,VRCSDK 有概率把你的同步分布两帧甚至更多,这取决于你的脚本的网络同步变量大小…… Continuous 同步模式会因为丢包导致不同步。 使用 NoVariableSync 同步模式的事件可能不可达。 等等等等…… 所以! 在设计网络同步的时候,我十分建议你注意以下的事情: 1、不要太多使用Continuous同步模式! 为什么要特地提这个呢?因为真的有很多人在滥用连续同步的连续,甚至为了使用连续同步把一些逻辑写进了 Update 里面。连续同步的更新速度很慢,做不到一秒一次,而且连续同步不会触发 OnDeserialization ,你无法得知你的变量什么时候同步了。 而且连续同步是有问题的,他并不保证变量最后是同步的,如果中途丢包了——他并不会重新同步。 但是手动同步是会保证抵达的,所以请不要太多使用 Continuous 同步模式!(或者说丢包概率更低,但并不是没有) 如果你执意使用,Udon 其实可以对一个【同步变量】(注意,这个要求这个变量必须是网络同步变量)使用 【FieldChangeCallback】 去做一个监控事件,在其被读取或者被修改的时候触发指定的逻辑。 他的写法如下: [UdonSynced, FieldChangeCallback(nameof(SyncedVariable))] private int _syncedVariable; public int SyncedVariable { get => _syncedToggle; set { _syncedVariable = value; //你可以在下面调用一个函数,或者任何你想干的事情 } } 实际使用方法: 将  FieldChangeCallback 属性应用到应用在变量上,并且指定 CallBack 的函数 写出对应指定 CallBack 的函数 在你想应用的变量的  FieldChangeCallback 属性参数参数中设置第二个属性的名称 冷知识,你可以通过 None 同步方法让你的本地脚本也支持这个功能。 2、在你使用 Manual 同步时,请尽量压缩你的同步变量,哪怕你觉得其实不是很大 因为当你拥有多个同步变量的时候, OnDeserialization 会在网络完成同步后触发,但是不代表所有的变量都完成了同步,所以你有责任压缩每一个脚本的同步变量大小,使他们可以在一帧中完全同步。否则我建议你为每个变量都建立监控事件(因为你的  OnDeserialization 事件已经变得不可靠了) 3、 OnDeserialization() 可以让你的网络同步变得简单,你知道像如下的方法来做…… 当你的主机进行了同步请求之后,你可以手动触发 OnDeserialization() 事件。 也就是说:但如果你在脚本中 Override 了 OnDeserialization() 事件,如果你希望所有人(包括主机)的表现一致。你应该在同步之后在主机手动触发 OnDeserialization() ,并且把所有的和这些参数有关的逻辑写在  OnDeserialization() 里面 [udonsync]public int Variable; public void SetsyncedVariable() { Networking.SetOwner(Networking.LocalPlayer, this.gameObject); RequestSerialization(); OnDeserialization() } public override void OnDeserialization() { //网络同步后的逻辑 } 4、请务必提前使用U#的 [UdonBehaviourSyncMode()] 属性把你的同步模式写死在脚本里! using UdonSharp; using UnityEngine; [UdonBehaviourSyncMode(BehaviourSyncMode.Manual)] public class Udon123 : UdonSharpBehaviour { // ... } 5、针对一些需要同步但不需要全面同步(手动同步)参数。你应该使用VRC最新的带参同步。 这个问题比较简单,这里直接教你该怎么写: [NetworkCallable] public void Network(int A , int B) { //AABBCC } 请注意:使用这个你需要占用上传带宽。我不保证在 NoVariableSync 同步模式这个能正常运行。 6、有些人可能会教你使用 NoVariableSync 同步模式, 但是答应我,请不要用他 这个同步模式有很都很奇怪的Bug,请答应我只使用VRCSDK本来有的三个同步方式,手动(Manual),连续(Continuous),不同步(None) 7、请尽量不要将 String 变成同步变量。 原因:String 的性质导致了你不能确定 String 的大小——他很方便,也很浪费性能。 8:不要通过同步 DisplayName 来同步玩家信息! 你应该通过 GetPlayerCount 获得玩家的全局唯一 ID,然后把这个 ID 传递到其他玩家,并让他们使用  VRCPlayerApi.GetPlayerById( ) 方法来获取 PlayerAPI,再获取 Displayname 。 我知道你会有很多诸如:内存消耗,性能问题等等,但是我需要提到的是: 在网络同步面前,这一切都不应该放在首位,网络同步的稳定才是首位,你应该优先你的网络同步稳定,然后再是其他的问题。 9:事件同步很好用,非常好用,而且对网络没有任何负担(相比于其他)。 如果可以你应该多用用,真的。