void ReplicateDependencies(ref NetMsgs.ReplicatedObjectData packet) { Perf.Begin("ActorReplicationChannel.ReplicateDependencies"); // Serialize referenced actors. objectRefs2.Clear(); while (objectRefs.Values.Count > 0) { Utils.Swap(ref objectRefs, ref objectRefs2); for (int i = 0; i < objectRefs2.Values.Count; ++i) { int netIDHashCode = objectRefs2.Values[i]; var obj = connection.world.GetObjectByNetIDHashCode(netIDHashCode); bool isOwner = true; bool isRelevant = true; var actor = obj as Actor; ObjectReplicator replicator = null; if (actor != null) { Assert.IsFalse(actor.disposed); if (actor.internal_NetTearOff) { continue; } isOwner = actor.ownerConnectionID == _connection.id; if (!isOwner && actor.ownerOnly) { // actor is not replicated on this channel. continue; } if (!CheckRelevancy(actor, out replicator, out isRelevant)) { // actor is not replicated on this channel. continue; } } else { var component = obj as ActorComponent; if (component != null) { isOwner = component.owner.ownerConnectionID == _connection.id; if (!isOwner && component.owner.ownerOnly) { // only replicate to owner. continue; } } } ReplicateObject(0f, obj, actor, replicator, isOwner, isRelevant, ref packet); #if !PACKET_COMBINE packet = packet.Flush(connection); #endif } objectRefs2.Clear(); } Perf.End(); }
public void HandleReplicatedObjectData(NetMsgs.ReplicatedObjectData objectData) { #if PACKET_COMBINE while (true) { objectData.archive.Discard(); if (objectData.archive.EOS) { break; } #endif InternalHandleReplicatedObjectData(objectData); #if PACKET_COMBINE } #else if (!objectData.archive.EOS) { throw new System.IO.IOException("Replicated object data did not consume its entire payload."); } #endif }
void InternalHandleReplicatedObjectData(NetMsgs.ReplicatedObjectData objectData) { #if PROFILING try { Perf.Begin("ActorReplicationChannel.InternalHandleReplicatedObjectData"); #endif CHECK_FLD(objectData.archive); var netID = objectData.archive.ReadUShort(); CHECK_FLD(objectData.archive); var obj = _connection.world.GetObjectByNetID(netID); var create = objectData.archive.ReadUnsignedBits(1) != 0; var relevant = objectData.archive.ReadUnsignedBits(1) != 0; var tearOff = objectData.archive.ReadUnsignedBits(1) != 0; CHECK_FLD(objectData.archive); ObjectReplicator replicator; if (obj == null) { if (!create) { throw new ActorReplicationException("Actor replication error (no actor with id " + netID + " and create flag not set)!"); } var netIDOuter = objectData.archive.ReadUShort(); var outerObj = _connection.world.GetObjectByNetID(netIDOuter); var classID = objectData.archive.ReadInt(); CHECK_FLD(objectData.archive); obj = _connection.world.InternalCreateReplicatedObject(classID, netID); replicator = new ObjectReplicator(this, obj, _connection.world.InternalGetReplicatedFields(obj), false); obj.internal_SetReplicator(connection, replicator); obj.PreConstruct(outerObj); obj.PreNetConstruct(); } else { if (create) { throw new ActorReplicationException("Actor replication error (actor with id " + netID + " create flag not set)!"); } replicator = obj.internal_GetReplicator(connection); } var actor = obj as Actor; bool wasRelevant = true; if (actor != null) { wasRelevant = actor.isNetRelevant; actor.internal_NetRelevant = relevant; } obj.PreNetReceive(); isSending = false; replicator.DeltaSerialize(0f, objectData.archive, false); obj.SerializeCustomData(objectData.archive); CHECK_FLD(objectData.archive); obj.PostNetReceive(); if (create) { obj.Construct(); obj.PostNetConstruct(); obj.PostConstruct(); } replicator.OnRep(); obj.PostOnRepFields(); if (create && (actor != null) && !_connection.world.isTraveling) { actor.OnLevelStart(); } IntHashtableList<ObjectReplicator> repls; if (pendingRefs.TryGetValue(obj.netIDHashCode, out repls)) { for (int i = 0; i < repls.Values.Count; ++i) { repls.Values[i].ResolveReference(obj, netID); } for (int i = 0; i < repls.Values.Count; ++i) { repls.Values[i].OnRep(); } repls.Clear(); } if ((actor != null) && (wasRelevant != relevant)) { actor.OnNetRelevancyChanged(); } if ((actor != null) && tearOff) { obj.internal_SetReplicator(connection, null); actor.NetTearOff(); } #if PROFILING } finally { Perf.End(); } #endif }
void ReplicateObject(float dt, SerializableObject obj, Actor actor, ObjectReplicator replicator, bool isOwner, bool isRelevant, ref NetMsgs.ReplicatedObjectData msg) { Perf.Begin("ActorReplicationChannel.ReplicateObject"); Assert.IsFalse((actor != null) ? actor.netTornOff : false); bool wroteAnything = false; // start on a byte boundary so we can restore the position to this point if we don't write any data. msg.archive.Flush(); msg = msg.MaybeSend(connection); var position = msg.archive.Position; bool relevancyChanged = true; CHECK_FLD(msg.archive); if (replicator == null) { replicator = obj.internal_GetReplicator(connection); } if (replicator == null) { replicator = new ObjectReplicator(this, obj, connection.world.InternalGetReplicatedFields(obj), isOwner); obj.internal_SetReplicator(connection, replicator); msg.archive.Write((ushort)obj.netID); CHECK_FLD(msg.archive); // actor has not been replicated yet msg.archive.WriteUnsignedBits(1, 1); msg.archive.WriteUnsignedBits(isRelevant ? 1 : 0, 1); msg.archive.WriteUnsignedBits(((actor != null) && (actor.internal_NetTearOff)) ? 1 : 0, 1); CHECK_FLD(msg.archive); msg.archive.Write((ushort)((obj.outer is SerializableObject) ? (obj.outer as SerializableObject).netID : 0)); msg.archive.Write(obj.classID); CHECK_FLD(msg.archive); replicator.FullSerialize(dt, msg.archive); SerializeCustomData(obj, msg.archive); wroteAnything = true; } else { relevancyChanged = replicator.wasRelevant != isRelevant; bool replicate = true; if ((dt >= 0f) && (actor != null) && !actor.internal_NetTearOff && !actor.internal_NetFlush && !relevancyChanged) { replicator.serializeDeltaTime += dt; if (replicator.serializeDeltaTime < actor.replicateRate) { replicate = false; } } if (replicate) { msg.archive.Write((ushort)obj.netID); CHECK_FLD(msg.archive); msg.archive.WriteUnsignedBits(0, 1); msg.archive.WriteUnsignedBits(isRelevant ? 1 : 0, 1); msg.archive.WriteUnsignedBits(((actor != null) && (actor.internal_NetTearOff)) ? 1 : 0, 1); CHECK_FLD(msg.archive); wroteAnything = replicator.DeltaSerialize(dt, msg.archive, (actor != null) && (actor.internal_NetFlush || relevancyChanged)); wroteAnything = SerializeCustomData(obj, msg.archive) || wroteAnything; } } if (wroteAnything || ((actor != null) && (actor.internal_NetFlush || relevancyChanged))) { CHECK_FLD(msg.archive); obj.SerializeSubobjects(this); } else { msg.archive.Position = position; msg.archive.Discard(); } replicator.wasRelevant = isRelevant; if ((actor != null) && actor.internal_NetTearOff) { obj.internal_SetReplicator(connection, null); } Perf.End(); }