具有NetworkIdentity组件的游戏物体可以带有多个从NetworkBehaviour派生出来的脚本,这些物体的序列化流程为:
在服务器上:
- 每个NetworkBehaviour上都有一个脏数据掩码,这个掩码可以在OnSerialize函数中通过syncVarDirtyBits访问到
- NetworkBehavious中的每个同步变量被指定了脏数据掩码中的一位
- 对同步变量的修改会使对应的脏数据位被设置
- 或者可以通过调用SetDirtyBit函数直接修改脏数据标志位
- 服务器的每个Update调用都会检查他的NetworkIdentity组件
- 如果有标记为脏的NetworkBehaviour,就会为那个物体创建一个更新数据包
- 每个NetworkBehaviour组件的OnSerialize函数都被调用,来构建这个更新数据包
- 没有脏数据位设置的NetworkBehaviour在数据包中添加0标志
- 有脏数据位设置的NetworkBehavious写入他们的脏数据和有改动的同步变量的值
- 如果一个NetworkBehavious的OnSerialize函数返回了True,那么他的脏标志位被重置,因此直到下一次数据修改之前不会被再次发送
- 更新数据包被发送到能看见这个物体的所有客户端
在客户端:
- 接收到一个物体的更新数据包
- 每个NetworkBehavious脚本的OnDeserialize函数被调用
- 这个物体上的每个NetworkBehavious脚本读取脏数据标识
- 如果关联到这个NetworkBehaviour脚本的脏数据位是0,OnDeserialize函数直接返回;
- 如果脏数据标志不是0,OnDeserialize函数继续读取后续的同步变量
- 如果有同步变量的钩子函数,调用钩子函数
对下面的代码:
public class data :NetworkBehaviour
{
[SyncVar]
public int int1 = 66;
[SyncVar]
public int int2 = 23487;
[SyncVar]
public string MyString = "esfdsagsdfgsdgdsfg";
}
产生的序列化函数OnSerialize将如下所示:
public override boolOnSerialize(NetworkWriter writer, bool forceAll)
{
if (forceAll)
{
// 第一次发送物体信息给客户端,发送全部数据
writer.WritePackedUInt32((uint)this.int1);
writer.WritePackedUInt32((uint)this.int2);
writer.Write(this.MyString);
return true;
}
bool wroteSyncVar = false;
if ((base.get_syncVarDirtyBits() & 1u) != 0u)
{
if (!wroteSyncVar)
{
// write dirty bits if this is the first SyncVar written
writer.WritePackedUInt32(base.get_syncVarDirtyBits());
wroteSyncVar = true;
}
writer.WritePackedUInt32((uint)this.int1);
}
if ((base.get_syncVarDirtyBits() & 2u) != 0u)
{
if (!wroteSyncVar)
{
// write dirty bits if this is the first SyncVar written
writer.WritePackedUInt32(base.get_syncVarDirtyBits());
wroteSyncVar = true;
}
writer.WritePackedUInt32((uint)this.int2);
}
if ((base.get_syncVarDirtyBits() & 4u) != 0u)
{
if (!wroteSyncVar)
{
// write dirty bits if this is the first SyncVar written
writer.WritePackedUInt32(base.get_syncVarDirtyBits());
wroteSyncVar = true;
}
writer.Write(this.MyString);
}
if (!wroteSyncVar)
{
// write zero dirty bits if no SyncVars were written
writer.WritePackedUInt32(0);
}
return wroteSyncVar;
}
反序列化函数将如下:
public override voidOnDeserialize(NetworkReader reader, bool initialState)
{
if (initialState)
{
this.int1 = (int)reader.ReadPackedUInt32();
this.int2 = (int)reader.ReadPackedUInt32();
this.MyString = reader.ReadString();
return;
}
int num = (int)reader.ReadPackedUInt32();
if ((num & 1) != 0)
{
this.int1 = (int)reader.ReadPackedUInt32();
}
if ((num & 2) != 0)
{
this.int2 = (int)reader.ReadPackedUInt32();
}
if ((num & 4) != 0)
{
this.MyString = reader.ReadString();
}
}
如果这个NetworkBehaviour的基类也有一个序列化函数,基类的序列化函数也将被调用。
注意更新数据包可能会在缓冲区中合并,所以一个传输层数据包可能包含多个物体的更新数据包。
unity5.1 Unet同步问题总结 (2)
内容版权声明:除非注明,否则皆为本站原创文章。