mirror of
https://github.com/MirrorNetworking/Mirror.git
synced 2024-11-18 02:50:32 +00:00
NetworkIdentity: SerializeServer split into Spawn and Broadcast to prepare for Unreliable sync method
This commit is contained in:
parent
43365aee5a
commit
32939d129e
@ -924,9 +924,9 @@ internal static bool IsDirty(ulong mask, int index)
|
|||||||
return (mask & nthBit) != 0;
|
return (mask & nthBit) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// serialize components into writer on the server.
|
// serialize server components, with full state for spawn message.
|
||||||
// check ownerWritten/observersWritten to know if anything was written
|
// check ownerWritten/observersWritten to know if anything was written
|
||||||
internal void SerializeServer(bool initialState, NetworkWriter ownerWriter, NetworkWriter observersWriter)
|
internal void SerializeServer_Spawn(NetworkWriter ownerWriter, NetworkWriter observersWriter)
|
||||||
{
|
{
|
||||||
// ensure NetworkBehaviours are valid before usage
|
// ensure NetworkBehaviours are valid before usage
|
||||||
ValidateComponents();
|
ValidateComponents();
|
||||||
@ -939,7 +939,7 @@ internal void SerializeServer(bool initialState, NetworkWriter ownerWriter, Netw
|
|||||||
// instead of writing a 1 byte index per component,
|
// instead of writing a 1 byte index per component,
|
||||||
// we limit components to 64 bits and write one ulong instead.
|
// we limit components to 64 bits and write one ulong instead.
|
||||||
// the ulong is also varint compressed for minimum bandwidth.
|
// the ulong is also varint compressed for minimum bandwidth.
|
||||||
(ulong ownerMask, ulong observerMask) = ServerDirtyMasks(initialState);
|
(ulong ownerMask, ulong observerMask) = ServerDirtyMasks(true);
|
||||||
|
|
||||||
// if nothing dirty, then don't even write the mask.
|
// if nothing dirty, then don't even write the mask.
|
||||||
// otherwise, every unchanged object would send a 1 byte dirty mask!
|
// otherwise, every unchanged object would send a 1 byte dirty mask!
|
||||||
@ -973,7 +973,7 @@ internal void SerializeServer(bool initialState, NetworkWriter ownerWriter, Netw
|
|||||||
// serialize into helper writer
|
// serialize into helper writer
|
||||||
using (NetworkWriterPooled temp = NetworkWriterPool.Get())
|
using (NetworkWriterPooled temp = NetworkWriterPool.Get())
|
||||||
{
|
{
|
||||||
comp.Serialize(temp, initialState);
|
comp.Serialize(temp, true);
|
||||||
ArraySegment<byte> segment = temp.ToArraySegment();
|
ArraySegment<byte> segment = temp.ToArraySegment();
|
||||||
|
|
||||||
// copy to owner / observers as needed
|
// copy to owner / observers as needed
|
||||||
@ -981,18 +981,76 @@ internal void SerializeServer(bool initialState, NetworkWriter ownerWriter, Netw
|
|||||||
if (observersDirty) observersWriter.WriteBytes(segment.Array, segment.Offset, segment.Count);
|
if (observersDirty) observersWriter.WriteBytes(segment.Array, segment.Offset, segment.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear dirty bits for the components that we serialized.
|
// dirty bits indicate 'changed since last delta sync'.
|
||||||
// do not clear for _all_ components, only the ones that
|
// don't clear then on full sync here, since full sync
|
||||||
// were dirty and had their syncInterval elapsed.
|
// is called whenever a new player spawns and needs the
|
||||||
//
|
// full state!
|
||||||
// we don't want to clear bits before the syncInterval
|
//comp.ClearAllDirtyBits();
|
||||||
// was elapsed, as then they wouldn't be synced.
|
}
|
||||||
//
|
}
|
||||||
// only clear for delta, not for full (spawn messages).
|
}
|
||||||
// otherwise if a player joins, we serialize monster,
|
}
|
||||||
// and shouldn't clear dirty bits not yet synced to
|
|
||||||
// other players.
|
// serialize server components, with delta state for broadcast messages.
|
||||||
if (!initialState) comp.ClearAllDirtyBits();
|
// check ownerWritten/observersWritten to know if anything was written
|
||||||
|
internal void SerializeServer_Broadcast(NetworkWriter ownerWriter, NetworkWriter observersWriter)
|
||||||
|
{
|
||||||
|
// ensure NetworkBehaviours are valid before usage
|
||||||
|
ValidateComponents();
|
||||||
|
NetworkBehaviour[] components = NetworkBehaviours;
|
||||||
|
|
||||||
|
// check which components are dirty for owner / observers.
|
||||||
|
// this is quite complicated with SyncMode + SyncDirection.
|
||||||
|
// see the function for explanation.
|
||||||
|
//
|
||||||
|
// instead of writing a 1 byte index per component,
|
||||||
|
// we limit components to 64 bits and write one ulong instead.
|
||||||
|
// the ulong is also varint compressed for minimum bandwidth.
|
||||||
|
(ulong ownerMask, ulong observerMask) = ServerDirtyMasks(false);
|
||||||
|
|
||||||
|
// if nothing dirty, then don't even write the mask.
|
||||||
|
// otherwise, every unchanged object would send a 1 byte dirty mask!
|
||||||
|
if (ownerMask != 0) Compression.CompressVarUInt(ownerWriter, ownerMask);
|
||||||
|
if (observerMask != 0) Compression.CompressVarUInt(observersWriter, observerMask);
|
||||||
|
|
||||||
|
// serialize all components
|
||||||
|
// perf: only iterate if either dirty mask has dirty bits.
|
||||||
|
if ((ownerMask | observerMask) != 0)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < components.Length; ++i)
|
||||||
|
{
|
||||||
|
NetworkBehaviour comp = components[i];
|
||||||
|
|
||||||
|
// is the component dirty for anyone (owner or observers)?
|
||||||
|
// may be serialized to owner, observer, both, or neither.
|
||||||
|
//
|
||||||
|
// OnSerialize should only be called once.
|
||||||
|
// this is faster, and it cleaner because it may set
|
||||||
|
// internal state, counters, logs, etc.
|
||||||
|
//
|
||||||
|
// previously we always serialized to owner and then copied
|
||||||
|
// the serialization to observers. however, since
|
||||||
|
// SyncDirection it's not guaranteed to be in owner anymore.
|
||||||
|
// so we need to serialize to temporary writer first.
|
||||||
|
// and then copy as needed.
|
||||||
|
bool ownerDirty = IsDirty(ownerMask, i);
|
||||||
|
bool observersDirty = IsDirty(observerMask, i);
|
||||||
|
if (ownerDirty || observersDirty)
|
||||||
|
{
|
||||||
|
// serialize into helper writer
|
||||||
|
using (NetworkWriterPooled temp = NetworkWriterPool.Get())
|
||||||
|
{
|
||||||
|
comp.Serialize(temp, false);
|
||||||
|
ArraySegment<byte> segment = temp.ToArraySegment();
|
||||||
|
|
||||||
|
// copy to owner / observers as needed
|
||||||
|
if (ownerDirty) ownerWriter.WriteBytes(segment.Array, segment.Offset, segment.Count);
|
||||||
|
if (observersDirty) observersWriter.WriteBytes(segment.Array, segment.Offset, segment.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
// dirty bits indicate 'changed since last delta sync'.
|
||||||
|
// clear them after a delta sync here.
|
||||||
|
comp.ClearAllDirtyBits();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1143,9 +1201,8 @@ internal NetworkIdentitySerialization GetServerSerializationAtTick(int tick)
|
|||||||
lastSerialization.ResetWriters();
|
lastSerialization.ResetWriters();
|
||||||
|
|
||||||
// serialize
|
// serialize
|
||||||
SerializeServer(false,
|
SerializeServer_Broadcast(lastSerialization.ownerWriter,
|
||||||
lastSerialization.ownerWriter,
|
lastSerialization.observersWriter);
|
||||||
lastSerialization.observersWriter);
|
|
||||||
|
|
||||||
// set tick
|
// set tick
|
||||||
lastSerialization.tick = tick;
|
lastSerialization.tick = tick;
|
||||||
|
@ -1405,7 +1405,7 @@ static ArraySegment<byte> CreateSpawnMessagePayload(bool isOwner, NetworkIdentit
|
|||||||
|
|
||||||
// serialize all components with initialState = true
|
// serialize all components with initialState = true
|
||||||
// (can be null if has none)
|
// (can be null if has none)
|
||||||
identity.SerializeServer(true, ownerWriter, observersWriter);
|
identity.SerializeServer_Spawn(ownerWriter, observersWriter);
|
||||||
|
|
||||||
// convert to ArraySegment to avoid reader allocations
|
// convert to ArraySegment to avoid reader allocations
|
||||||
// if nothing was written, .ToArraySegment returns an empty segment.
|
// if nothing was written, .ToArraySegment returns an empty segment.
|
||||||
|
@ -50,7 +50,7 @@ public void SerializeAndDeserializeAll()
|
|||||||
serverObserversComp.value = 42;
|
serverObserversComp.value = 42;
|
||||||
|
|
||||||
// serialize server object
|
// serialize server object
|
||||||
serverIdentity.SerializeServer(true, ownerWriter, observersWriter);
|
serverIdentity.SerializeServer_Spawn(ownerWriter, observersWriter);
|
||||||
|
|
||||||
// deserialize client object with OWNER payload
|
// deserialize client object with OWNER payload
|
||||||
NetworkReader reader = new NetworkReader(ownerWriter.ToArray());
|
NetworkReader reader = new NetworkReader(ownerWriter.ToArray());
|
||||||
@ -96,7 +96,7 @@ public void SerializationException()
|
|||||||
// serialize server object
|
// serialize server object
|
||||||
// should work even if compExc throws an exception.
|
// should work even if compExc throws an exception.
|
||||||
// error log because of the exception is expected.
|
// error log because of the exception is expected.
|
||||||
serverIdentity.SerializeServer(true, ownerWriter, observersWriter);
|
serverIdentity.SerializeServer_Spawn(ownerWriter, observersWriter);
|
||||||
|
|
||||||
// deserialize client object with OWNER payload
|
// deserialize client object with OWNER payload
|
||||||
// should work even if compExc throws an exception
|
// should work even if compExc throws an exception
|
||||||
@ -187,7 +187,7 @@ public void SerializationMismatch()
|
|||||||
serverComp.value = "42";
|
serverComp.value = "42";
|
||||||
|
|
||||||
// serialize server object
|
// serialize server object
|
||||||
serverIdentity.SerializeServer(true, ownerWriter, observersWriter);
|
serverIdentity.SerializeServer_Spawn(ownerWriter, observersWriter);
|
||||||
|
|
||||||
// deserialize on client
|
// deserialize on client
|
||||||
// ignore warning log because of serialization mismatch
|
// ignore warning log because of serialization mismatch
|
||||||
@ -219,7 +219,7 @@ public void SerializeServer_NotInitial_NotDirty_WritesNothing()
|
|||||||
// serialize server object.
|
// serialize server object.
|
||||||
// 'initial' would write everything.
|
// 'initial' would write everything.
|
||||||
// instead, try 'not initial' with 0 dirty bits
|
// instead, try 'not initial' with 0 dirty bits
|
||||||
serverIdentity.SerializeServer(false, ownerWriter, observersWriter);
|
serverIdentity.SerializeServer_Broadcast(ownerWriter, observersWriter);
|
||||||
Assert.That(ownerWriter.Position, Is.EqualTo(0));
|
Assert.That(ownerWriter.Position, Is.EqualTo(0));
|
||||||
Assert.That(observersWriter.Position, Is.EqualTo(0));
|
Assert.That(observersWriter.Position, Is.EqualTo(0));
|
||||||
}
|
}
|
||||||
@ -292,7 +292,7 @@ public void SerializeServer_OwnerMode_ClientToServer()
|
|||||||
comp.SetValue(11); // modify with helper function to avoid #3525
|
comp.SetValue(11); // modify with helper function to avoid #3525
|
||||||
|
|
||||||
// initial: should still write for owner
|
// initial: should still write for owner
|
||||||
identity.SerializeServer(true, ownerWriter, observersWriter);
|
identity.SerializeServer_Spawn(ownerWriter, observersWriter);
|
||||||
Debug.Log("initial ownerWriter: " + ownerWriter);
|
Debug.Log("initial ownerWriter: " + ownerWriter);
|
||||||
Debug.Log("initial observerWriter: " + observersWriter);
|
Debug.Log("initial observerWriter: " + observersWriter);
|
||||||
Assert.That(ownerWriter.Position, Is.GreaterThan(0));
|
Assert.That(ownerWriter.Position, Is.GreaterThan(0));
|
||||||
@ -302,7 +302,7 @@ public void SerializeServer_OwnerMode_ClientToServer()
|
|||||||
comp.SetValue(22); // modify with helper function to avoid #3525
|
comp.SetValue(22); // modify with helper function to avoid #3525
|
||||||
ownerWriter.Position = 0;
|
ownerWriter.Position = 0;
|
||||||
observersWriter.Position = 0;
|
observersWriter.Position = 0;
|
||||||
identity.SerializeServer(false, ownerWriter, observersWriter);
|
identity.SerializeServer_Broadcast(ownerWriter, observersWriter);
|
||||||
Debug.Log("delta ownerWriter: " + ownerWriter);
|
Debug.Log("delta ownerWriter: " + ownerWriter);
|
||||||
Debug.Log("delta observersWriter: " + observersWriter);
|
Debug.Log("delta observersWriter: " + observersWriter);
|
||||||
Assert.That(ownerWriter.Position, Is.EqualTo(0));
|
Assert.That(ownerWriter.Position, Is.EqualTo(0));
|
||||||
@ -330,7 +330,7 @@ public void SerializeServer_ObserversMode_ClientToServer()
|
|||||||
comp.SetValue(11); // modify with helper function to avoid #3525
|
comp.SetValue(11); // modify with helper function to avoid #3525
|
||||||
|
|
||||||
// initial: should write something for owner and observers
|
// initial: should write something for owner and observers
|
||||||
identity.SerializeServer(true, ownerWriter, observersWriter);
|
identity.SerializeServer_Spawn(ownerWriter, observersWriter);
|
||||||
Debug.Log("initial ownerWriter: " + ownerWriter);
|
Debug.Log("initial ownerWriter: " + ownerWriter);
|
||||||
Debug.Log("initial observerWriter: " + observersWriter);
|
Debug.Log("initial observerWriter: " + observersWriter);
|
||||||
Assert.That(ownerWriter.Position, Is.GreaterThan(0));
|
Assert.That(ownerWriter.Position, Is.GreaterThan(0));
|
||||||
@ -340,7 +340,7 @@ public void SerializeServer_ObserversMode_ClientToServer()
|
|||||||
comp.SetValue(22); // modify with helper function to avoid #3525
|
comp.SetValue(22); // modify with helper function to avoid #3525
|
||||||
ownerWriter.Position = 0;
|
ownerWriter.Position = 0;
|
||||||
observersWriter.Position = 0;
|
observersWriter.Position = 0;
|
||||||
identity.SerializeServer(false, ownerWriter, observersWriter);
|
identity.SerializeServer_Broadcast(ownerWriter, observersWriter);
|
||||||
Debug.Log("delta ownerWriter: " + ownerWriter);
|
Debug.Log("delta ownerWriter: " + ownerWriter);
|
||||||
Debug.Log("delta observersWriter: " + observersWriter);
|
Debug.Log("delta observersWriter: " + observersWriter);
|
||||||
Assert.That(ownerWriter.Position, Is.EqualTo(0));
|
Assert.That(ownerWriter.Position, Is.EqualTo(0));
|
||||||
|
@ -404,7 +404,7 @@ public void TestSyncingAbstractNetworkBehaviour()
|
|||||||
NetworkWriter ownerWriter = new NetworkWriter();
|
NetworkWriter ownerWriter = new NetworkWriter();
|
||||||
// not really used in this Test
|
// not really used in this Test
|
||||||
NetworkWriter observersWriter = new NetworkWriter();
|
NetworkWriter observersWriter = new NetworkWriter();
|
||||||
serverIdentity.SerializeServer(true, ownerWriter, observersWriter);
|
serverIdentity.SerializeServer_Spawn(ownerWriter, observersWriter);
|
||||||
|
|
||||||
// set up a "client" object
|
// set up a "client" object
|
||||||
CreateNetworked(out _, out NetworkIdentity clientIdentity, out SyncVarAbstractNetworkBehaviour clientBehaviour);
|
CreateNetworked(out _, out NetworkIdentity clientIdentity, out SyncVarAbstractNetworkBehaviour clientBehaviour);
|
||||||
|
Loading…
Reference in New Issue
Block a user