在你正式开始网络同步之前——你最好知道的一些事
本文是我【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:事件同步很好用,非常好用,而且对网络没有任何负担(相比于其他)。
如果可以你应该多用用,真的。
No comments to display
No comments to display