perf: NetworkIdentity.Serialize now clears dirty bits while iterating. avoids O(N) ClearALlComponentsDirtyBits call after each Serialize call.

This commit is contained in:
vis2k 2022-11-12 11:36:59 +01:00
parent 91b0d43029
commit 1970ec523e
3 changed files with 26 additions and 22 deletions

View File

@ -1493,9 +1493,6 @@ static void Broadcast()
payload = writer.ToArraySegment()
};
Send(message);
// reset dirty bits so it's not resent next time.
identity.ClearAllComponentsDirtyBits();
}
}
}

View File

@ -974,9 +974,20 @@ internal void SerializeServer(bool initialState, NetworkWriter ownerWriter, Netw
if (ownerDirty) ownerWriter.WriteBytes(segment.Array, segment.Offset, segment.Count);
if (observersDirty) observersWriter.WriteBytes(segment.Array, segment.Offset, segment.Count);
}
// clear dirty bits after serializing.
// best to do it here while iterating.
// ClearAllComponentsDirtyBits would have to iterate
// everything again otherwise.
comp.ClearAllDirtyBits();
}
}
}
// clear dirty component bits as well.
// otherwise OnBecameDirty wouldn't detect initial dirty next time.
serverOwnerDirtyMask = 0;
serverObserversDirtyMask = 0;
}
// serialize components into writer on the client.
@ -1023,9 +1034,19 @@ internal void SerializeClient(NetworkWriter writer)
// serialize into writer.
// server always knows initialState, we never need to send it
comp.Serialize(writer, false);
// clear dirty bits after serializing.
// best to do it here while iterating.
// ClearAllComponentsDirtyBits would have to iterate
// everything again otherwise.
comp.ClearAllDirtyBits();
}
}
}
// clear dirty component bits as well.
// otherwise OnBecameDirty wouldn't detect initial dirty next time.
clientDirtyMask = 0;
}
// deserialize components from the client on the server.
@ -1112,21 +1133,6 @@ internal NetworkIdentitySerialization GetServerSerializationAtTick(int tick)
lastSerialization.ownerWriter,
lastSerialization.observersWriter);
// clear dirty bits for the components that we serialized.
// previously we did this in NetworkServer.BroadcastToConnection
// for every connection, for every entity.
// but we only serialize each entity once, right here in this
// 'lastSerialization.tick != tick' scope.
// so only do it once.
//
// NOTE: not in Serializell as that should only do one
// thing: serialize data.
//
// NOTE: this used to be very important to avoid ever growing
// SyncList changes if they had no observers, but we've
// added SyncObject.isRecording since.
ClearAllComponentsDirtyBits();
// set tick
lastSerialization.tick = tick;
//Debug.Log($"{name} (netId={netId}) serialized for tick={tickTimeStamp}");
@ -1330,13 +1336,17 @@ internal void Reset()
isLocalPlayer = false;
}
// clear all component's dirty bits no matter what
// clear all component's dirty bits no matter what.
// when serializing, it's best to clear them while already iterating.
// this way we don't need to iterate all components here again.
// this should only be used if we need to clear outside of serialization.
internal void ClearAllComponentsDirtyBits()
{
serverOwnerDirtyMask = 0;
serverObserversDirtyMask = 0;
clientDirtyMask = 0;
// TODO clear only the dirty ones? fine now without interval.
foreach (NetworkBehaviour comp in NetworkBehaviours)
{
comp.ClearAllDirtyBits();

View File

@ -346,9 +346,6 @@ public void SerializeServer_ObserversMode_ClientToServer()
Assert.That(ownerWriter.Position, Is.GreaterThan(0));
Assert.That(observersWriter.Position, Is.GreaterThan(0));
// reset dirty bits after serializing
identity.ClearAllComponentsDirtyBits();
// delta: should only write for observers
++comp.value; // change something
ownerWriter.Position = 0;