void RawNetRecv(ActorReplicationChannel channel, int size) { #if PROFILING try { Perf.Begin("World.RawNetRecv"); #endif _netArchive.BeginRead(size); int typeID = _netArchive.ReadInt(); NetMsg msg = _netMsgFactory.GetNetMsg(typeID); if (msg != null) { msg.Serialize(channel.connection, _netArchive); if (_netArchive.hasUnreadBytes) { throw new System.IO.IOException(msg.GetType().FullName + " did not consume its entire payload."); } DynamicDispatchNetMsg(msg, channel); } else { throw new System.IO.IOException("Unrecognized net message type " + typeID); } #if PROFILING } finally { Perf.End(); } #endif }
public void TickServer(float dt, byte[] recvBuffer, ref NetIOMetrics reliableChannelMetrics, ref NetIOMetrics unreliableChannelMetrics) { Perf.Begin("LocalGameNetDriver.TickServer"); if (serverSend != null) { if (serverSend.connectPending) { serverSend.connectPending = false; Assert.IsNotNull(clientSend); clientSend.connectPending = true; serverSend.callbacks.OnConnect(serverSend); } if ((serverSend != null) && (clientSendOfs > 0)) { RecvMessages(clientSendBuffer, clientSendOfs, recvBuffer, serverSend, ref reliableChannelMetrics, ref unreliableChannelMetrics); clientSendOfs = 0; } if ((serverSend != null) && (serverSend.disconnectPending)) { serverSend.Dispose(); serverSend = null; } } Perf.End(); }
protected virtual void TickActors(MonoBehaviour loadingContext) { Perf.Begin("World.TickActors"); _loadingQueue.Run(loadingContext); _taskQueue.Run(loadingContext); for (int i = 0; i < _actors.Count;) { var actor = _actors[i]; if (!actor.pendingKill) { actor.Tick(); actor.TickComponents(); actor.TickLifetime(); } if (actor.pendingKill) { DestroyActor(actor, false); _actors.RemoveAt(i); } else { ++i; } } Perf.End(); }
public void SendReliable(byte[] buffer, int numBytes) { Perf.Begin("LocalGameNetDriverConnection.SendReliable"); netDriver.SendReliable(this, buffer, numBytes); reliableMetrics.bytesSent += numBytes; ++reliableMetrics.numPacketsSent; Perf.End(); }
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 Write(NetArchive archive, ISerializableObjectReferenceCollector collector, object fieldVal, bool deltaField) { Perf.Begin("FieldState.Write"); fieldSpec.serializer.Serialize(archive, collector, ref fieldVal, deltaField ? lastState : null); if (deltaField) { lastState = fieldSpec.serializer.Copy(fieldVal); } Perf.End(); }
public void ReplicateRPC(SerializableObject context, int rpcID, ObjectRPCSerializer serializer, params object[] args) { if (!_connection.isValid) { return; } Perf.Begin("ActorReplicationChannel.ReplicateRPC"); if (isServer) { if (!didHandshake) { // client hasn't finished connecting Perf.End(); return; } if ((clientLevel == null) || (clientLevel != _connection.world.currentLevel)) { Perf.End(); return; } } else if (_connection.world.isTraveling) { Perf.End(); return; } if (context.internal_GetReplicator(connection) == null) { // has not been replicated. Perf.End(); return; } var actor = context as Actor; if ((actor != null) && isServer && serializer.rpcInfo.CheckRelevancy && !actor.IsNetRelevantFor(this)) { // not relevant Perf.End(); return; } Assert.IsFalse((actor != null) ? actor.netTornOff : false); objectRefs.Clear(); var netMsg = NetMsgs.ReplicatedObjectRPC.New(context.netID, (ushort)rpcID); serializer.Write(netMsg.archive, this, args); if (_connection.world is Server.ServerWorld) { // send objects in the argument list first ReplicateDependencies(); } else { objectRefs.Clear(); } _connection.SendReliable(netMsg); Perf.End(); }
internal void SendReliable(LocalGameNetDriverConnection conn, byte[] buffer, int numBytes) { Perf.Begin("LocalGameNetDriver.SendReliable"); if (conn == serverSend) { WriteMessage(buffer, numBytes, serverSendBuffer, ref serverSendOfs); } else { Assert.IsNotNull(clientSend); WriteMessage(buffer, numBytes, clientSendBuffer, ref clientSendOfs); } Perf.End(); }
bool CheckRelevancy(Actor actor, out ObjectReplicator repl, out bool isRelevant) { Perf.Begin("CheckRelevancy"); isRelevant = actor.IsNetRelevantFor(this); repl = actor.internal_GetReplicator(connection); if (repl != null) { if (repl.wasRelevant != isRelevant) { Perf.End(); return true; } } Perf.End(); return isRelevant; }
public void Ping(float dt) { Perf.Begin("Ping"); nextPingTime -= dt; if (nextPingTime <= 0f) { nextPingTime = PING_RATE; #if UNITY_EDITOR && !PROFILING pongTimeout = Mathf.Max(pongTimeout, maxPongTimeout); #else connection.SendReliable(NetMsgs.Ping.New(Utils.ReadMilliseconds())); #endif } pongTimeout -= Mathf.Min(dt, 1/3f); Perf.End(); }
protected virtual void FixedUpdateActors(float dt) { Perf.Begin("World.FixedUpdate"); for (int i = 0; i < _actors.Count; ++i) { var actor = _actors[i]; if (!actor.pendingKill) { actor.FixedUpdate(dt); } } Perf.End(); }
public void TickClient(float dt, byte[] recvBuffer, ref NetIOMetrics reliableChannelMetrics, ref NetIOMetrics unreliableChannelMetrics) { Perf.Begin("SocketNetDriver.TickClient"); if (_serverConnection != null) { bool wasReset = false; bool isDisposed = false; try { wasReset = _serverConnection.sockets[0].Poll(0, SelectMode.SelectRead); } catch (Exception) { isDisposed = true; } if (isDisposed || (wasReset && (_serverConnection.sockets[0].Available == 0))) { Debug.LogError("Server connection was reset."); _serverConnection.Dispose(); // don't set _serverConnection to null so NetDriverConnection's can be cleaned up correctly. Perf.End(); return; } Recv(_serverConnection, _clientCallbacks, _serverConnection.sockets[0], recvBuffer, ref reliableChannelMetrics, false); if (_serverConnection != null) { Recv(_serverConnection, _clientCallbacks, _serverConnection.sockets[1], recvBuffer, ref unreliableChannelMetrics, true); } if (_serverConnection != null) { if (!_serverConnection.didHandshake && (_serverConnection.channelID != -1)) { _sendUdpControlTimeout -= dt; if (_sendUdpControlTimeout <= 0f) { _sendUdpControlTimeout = UDP_CONTROL_RESEND_TIMEOUT; SendUdpControl(_serverConnection); } } } } Perf.End(); }
public void SendReliable(byte[] buffer, int numBytes) { Perf.Begin("SocketNetDriverConnection.SendReliable"); Assert.IsTrue(numBytes <= ushort.MaxValue); msgTemp[0] = (byte)(numBytes & 0xff); msgTemp[1] = (byte)((numBytes >> 8) & 0xff); try { Array.Copy(buffer, 0, msgTemp, 2, numBytes); numBytes += 2; int numTries = 0; int numSent = 0; do { var bytesSent = sockets[0].Send(msgTemp, numSent, numBytes - numSent, SocketFlags.None); numSent += bytesSent; } while ((numSent < numBytes) && (++numTries < 15)); if (numSent != numBytes) { throw new Exception("Reliable socket send did not send all bytes (tried to send " + numBytes + " byte(s) but only sent " + numSent + "."); } ++reliableMetrics.numPacketsSent; reliableMetrics.bytesSent += numBytes; } catch (Exception e) { Debug.LogException(e); var socketException = e as SocketException; if (socketException != null) { if (socketException.SocketErrorCode == SocketError.WouldBlock) { _driver.ReliableSendWouldBlock(this); return; } } Dispose(); } Perf.End(); }
public void SendUnreliable(byte[] buffer, int numBytes) { Perf.Begin("SocketNetDriverConnection.SendUnreliable"); try { var numSent = sockets[1].SendTo(buffer, 0, numBytes, SocketFlags.None, udpEndpoint); if (numSent != numBytes) { Debug.LogError("Unreliable socket send did not send all bytes (tried to send " + numBytes + " byte(s) but only sent " + numSent + "."); throw new SocketException((int)SocketError.SocketError); } ++unreliableMetrics.numPacketsSent; unreliableMetrics.bytesSent += numBytes; } catch (Exception e) { Debug.LogError("Unreliable socket send failed with exception (tried to send " + numBytes + " byte(s)."); Debug.LogException(e); Dispose(); } Perf.End(); }
void RecvMessages(byte[] src, int srcLen, byte[] dst, LocalGameNetDriverConnection conn, ref NetIOMetrics reliableChannelMetrics, ref NetIOMetrics unreliableChannelMetrics) { Perf.Begin("LocalGameNetDriver.RecvMessages"); for (int i = 0; i < srcLen - 4;) { if (!conn.isValid) { break; } int msgLen = System.BitConverter.ToInt32(src, i); i += 4; Assert.IsTrue(msgLen > 0); if (msgLen > 0) { System.Array.Copy(src, i, dst, 0, msgLen); try { Perf.Begin("LocalGameNetDriver.RecvMessages.Callbacks.OnMessageReceived"); conn.callbacks.OnMessageReceived(conn, dst, msgLen); Perf.End(); } catch (System.Exception e) { Debug.LogException(e); } } else { conn.callbacks.OnInvalidMessageReceived(conn); } i += msgLen; // increment before callback in-case there is an exception reliableChannelMetrics.bytesRecv += msgLen; ++reliableChannelMetrics.numPacketsRecv; } Perf.End(); }
protected virtual void LateTickActors() { Perf.Begin("World.LateTickActors"); for (int i = 0; i < _actors.Count;) { var actor = _actors[i]; if (!actor.pendingKill) { actor.LateTick(); } if (actor.pendingKill) { DestroyActor(actor, false); _actors.RemoveAt(i); } else { ++i; } } Perf.End(); }
bool SerializeFields(float dt, NetArchive archive, bool deltasOnly, bool netFlush) { Perf.Begin("SerializeFields"); ActorReplicationChannel.CHECK_FLD(archive); isLoading = archive.isLoading; if (isLoading) { byte numBits = archive.ReadByte(); Assert.IsTrue(numBits <= SerializedObjectFields.MAX_REPLICATED_FIELDS); uint fieldBits = archive.ReadUnsignedBits(numBits); ActorReplicationChannel.CHECK_FLD(archive); for (int i = 0; i < numBits; ++i) { if (((1U << i) & fieldBits) != 0) { var fieldState = fieldStates.Values[i]; curFieldState = fieldState; object obj = fieldState.fieldSpec.field.GetValue(_object); object orig = obj; ActorReplicationChannel.CHECK_FLD(archive); if (fieldState.fieldSpec.serializer.Serialize(archive, this, ref obj, null)) { fieldState.needsRep = fieldState.fieldSpec.onRep != null; if (fieldState.needsRep) { ++numOnReps; } } ActorReplicationChannel.CHECK_FLD(archive); if (obj != orig) { fieldState.fieldSpec.field.SetValue(_object, obj); } } } curFieldState = null; Perf.End(); return numBits > 0; } else { fieldsToReplicate.Clear(); byte numBitsWritten = 0; uint fieldBits = 0; for (int i = 0; i < fieldStates.Values.Count; ++i) { var field = fieldStates.Values[i]; object fieldVal; bool deltaField; if (field.IsDirty(channel, _object, dt, deltasOnly, hasReplicated, isOwner, netFlush, out fieldVal, out deltaField)) { numBitsWritten = (byte)(i + 1); fieldBits |= 1U << i; fieldsToReplicate.Add(new FieldReplicateInfo(i, fieldVal, deltaField)); } } Assert.IsTrue(numBitsWritten <= SerializedObjectFields.MAX_REPLICATED_FIELDS); archive.Write(numBitsWritten); archive.WriteUnsignedBits(fieldBits, numBitsWritten); ActorReplicationChannel.CHECK_FLD(archive); for (int i = 0; i < fieldsToReplicate.Count; ++i) { var info = fieldsToReplicate[i]; var field = fieldStates.Values[info.index]; ActorReplicationChannel.CHECK_FLD(archive); field.Write(archive, this, info.fieldVal, info.deltaField); ActorReplicationChannel.CHECK_FLD(archive); } fieldsToReplicate.Clear(); hasReplicated = true; Perf.End(); return numBitsWritten > 0; } }
public void TickServer(float dt, byte[] recvBuffer, ref NetIOMetrics reliableChannelMetrics, ref NetIOMetrics unreliableChannelMetrics) { Perf.Begin("SocketNetDriver.TickServer"); for (;;) { Socket newSocket; try { newSocket = _serverSock[0].Accept(); } catch (SocketException) { break; } if (_tcpConnections.ContainsKey(newSocket.RemoteEndPoint)) { Debug.LogError("Connection attempt from already connected client!"); newSocket.Close(); continue; } var clientSocks = new Socket[2]; clientSocks[0] = newSocket; clientSocks[1] = _serverSock[1]; newSocket.Blocking = false; //newSocket.NoDelay = true; newSocket.SendBufferSize = World.MAX_RELIABLE_MESSAGE_SIZE * 8; newSocket.SendTimeout = 500; var newConn = new SocketNetDriverConnection(this, clientSocks, nextChannelID++); _tcpConnections.Add(newSocket.RemoteEndPoint, newConn); SendTcpControl(newConn); } for (int i = 0; i < _tcpConnections.Values.Count;) { var c = _tcpConnections.Values[i]; bool wasReset = false; bool isDisposed = false; try { wasReset = c.sockets[0].Poll(0, SelectMode.SelectRead); } catch (Exception) { isDisposed = true; } if (isDisposed || (wasReset && (c.sockets[0].Available == 0))) { c.Dispose(); continue; } Recv(c, _serverCallbacks, c.sockets[0], recvBuffer, ref reliableChannelMetrics, false); if (c.isValid && !c.didHandshake) { c.handshakeTime += dt; if (c.handshakeTime > UDP_CONTROL_DISCONNECT_TIMEOUT) { // handshake failed Debug.LogError("Disconnecting " + c.tcpEndpoint.ToString() + ": udp handshake timed out"); c.Dispose(); } } if (c.isValid) { ++i; } } RecvFrom(_serverCallbacks, _serverSock[1], recvBuffer, ref unreliableChannelMetrics); Perf.End(); }
public bool IsDirty(ActorReplicationChannel channel, SerializableObject container, float dt, bool deltasOnly, bool hasReplicated, bool isOwner, bool netFlush, out object fieldValue, out bool deltaField) { Perf.Begin("FieldState.IsDirty"); bool shouldReplicate = true; if (fieldSpec.replication.Condition != EReplicateCondition.Always) { switch (fieldSpec.replication.Condition) { case EReplicateCondition.InitialOnly: shouldReplicate = !hasReplicated; break; case EReplicateCondition.OwnerOnly: shouldReplicate = isOwner; break; case EReplicateCondition.SkipOwner: shouldReplicate = !isOwner; break; case EReplicateCondition.InitialOrOwner: shouldReplicate = !hasReplicated || isOwner; break; case EReplicateCondition.InitialOwnerOnly: shouldReplicate = !hasReplicated && isOwner; break; } } if (!shouldReplicate) { deltaField = false; fieldValue = null; Perf.End(); return false; } if (!netFlush) { nextSendTime -= dt; if (nextSendTime > 0f) { deltaField = false; fieldValue = null; Perf.End(); return false; } } // Update send time here: if we don't send because the value hasn't changed // we don't want to check again until after the UpdateRate has passed. nextSendTime = fieldSpec.replication.UpdateRate; fieldValue = fieldSpec.field.GetValue(container); // check ownerOnly object replication. if (fieldSpec.isObjectReference) { var actor = fieldValue as Actor; if ((actor != null) && actor.ownerOnly) { if (actor.ownerConnection != channel) { deltaField = false; Perf.End(); return false; } } } deltaField = !fieldSpec.serializer.FieldsAreEqual(lastState, fieldValue); if (deltasOnly && !deltaField) { Perf.End(); return false; } Perf.End(); return true; }
void Recv(SocketNetDriverConnection connection, INetDriverCallbacks callbacks, Socket socket, byte[] buffer, ref NetIOMetrics metrics, bool isDatagram) { Perf.Begin("SocketNetDriver.Recv"); if (isDatagram) { while (connection.isValid && (socket.Available > 0)) { int r; try { r = socket.Receive(buffer, 0, World.MAX_UNRELIABLE_MESSAGE_SIZE, SocketFlags.None); if (r <= 0) { throw new SocketException((int)SocketError.SocketError); } metrics.bytesRecv += r; ++metrics.numPacketsRecv; } catch (Exception e) { Debug.LogException(e); callbacks.OnInvalidMessageReceived(connection); continue; } if (!connection.didHandshake) { // client may receive a UDP packet before receiving control ACK // so discard the packet until we process the ACK. continue; } callbacks.OnMessageReceived(connection, buffer, r); } } else { while (connection.isValid && (socket.Available > 0)) { if (connection.pendingRecvSize <= 0) { if (socket.Available < 2) { break; } // read from socket. if (socket.Receive(connection.pendingBytes, 0, 2, SocketFlags.None) != 2) { throw new SocketException((int)SocketError.SocketError); } connection.pendingRecvSize = ((int)connection.pendingBytes[0]) | (((int)connection.pendingBytes[1]) << 8); connection.pendingBytesReceived = 0; if (connection.pendingRecvSize > connection.pendingBytes.Length) { callbacks.OnInvalidMessageReceived(connection); continue; } } { // read from socket. var numBytesToRead = Mathf.Min(socket.Available, connection.pendingRecvSize - connection.pendingBytesReceived); if (numBytesToRead > 0) { if (socket.Receive(connection.pendingBytes, connection.pendingBytesReceived, numBytesToRead, SocketFlags.None) != numBytesToRead) { throw new SocketException((int)SocketError.SocketError); } connection.pendingBytesReceived += numBytesToRead; } } Assert.IsTrue(connection.pendingBytesReceived <= connection.pendingRecvSize); if (connection.pendingBytesReceived >= connection.pendingRecvSize) { if (!connection.didHandshake) { if (callbacks == _clientCallbacks) { if (connection.channelID == -1) { var id = RecvControl(connection.pendingBytes, connection.pendingRecvSize); if (id == -1) { connection.Dispose(); break; } connection.channelID = id; _sendUdpControlTimeout = UDP_CONTROL_RESEND_TIMEOUT; SendUdpControl(connection); } else if (connection.pendingBytes[0] == (byte)EControlCode.AckChannelID) { connection.didHandshake = true; callbacks.OnConnect(connection); } else { // invalid response connection.Dispose(); break; } } else { connection.Dispose(); break; } connection.pendingRecvSize = 0; connection.pendingBytesReceived = 0; continue; } Array.Copy(connection.pendingBytes, buffer, connection.pendingRecvSize); var r = connection.pendingRecvSize; connection.pendingBytesReceived = 0; connection.pendingRecvSize = 0; metrics.bytesRecv += r; ++metrics.numPacketsRecv; callbacks.OnMessageReceived(connection, buffer, r); continue; } // not enough data ready break; } } Perf.End(); }
void RecvFrom(INetDriverCallbacks callbacks, Socket socket, byte[] buffer, ref NetIOMetrics metrics) { Perf.Begin("SocketNetDriver.RecvFrom"); while (socket.Available > 0) { int r; try { r = socket.ReceiveFrom(buffer, 0, World.MAX_UNRELIABLE_MESSAGE_SIZE, SocketFlags.None, ref _recvEndPoint); } catch (Exception e) { Debug.LogException(e); SocketNetDriverConnection conn; if (_udpConnections.TryGetValue(_recvEndPoint, out conn)) { callbacks.OnInvalidMessageReceived(conn); } continue; } if (r <= 0) { throw new SocketException((int)SocketError.SocketError); } metrics.bytesRecv += r; ++metrics.numPacketsRecv; SocketNetDriverConnection connection; if (_udpConnections.TryGetValue(_recvEndPoint, out connection)) { if (connection.isValid) { if (r > 3) { // currently NetMsgs are always more than 3 bytes, and this guarantees that we don't // try to process a duplicated control udp control message. callbacks.OnMessageReceived(connection, buffer, r); } } } else { // is this a control code? var id = RecvControl(buffer, r); if (id != -1) { for (int i = 0; i < _tcpConnections.Values.Count; ++i) { var c = _tcpConnections.Values[i]; if (c.channelID == id) { if (_udpConnections.Values.Contains(c)) { Debug.LogWarning("UDP control message received for registered channel."); } else { c.udpEndpoint = new IPEndPoint(((IPEndPoint)_recvEndPoint).Address, ((IPEndPoint)_recvEndPoint).Port); _udpConnections.Add(c.udpEndpoint, c); SendTcpControlAck(c); c.didHandshake = true; callbacks.OnConnect(c); break; } } } } } } Perf.End(); }
public void ReplicateActors(float dt) { if (!didHandshake) { handshakeTime += Mathf.Min(dt, 1/3f); // client hasn't finished connecting return; } Ping(dt); if (!clientLevelLoaded) { ResetTimeoutForTravel(); return; } Perf.Begin("ActorReplicationChannel.ReplicateActors"); isSending = true; objectRefs.Clear(); var packet = NetMsgs.ReplicatedObjectData.New(); for (int i = 0; i < connection.world.numReplicatedActors; ++i) { var actor = connection.world.GetReplicatedActor(i); Assert.IsFalse(actor.disposed); var isOwner = actor.ownerConnectionID == _connection.id; if (!isOwner && actor.ownerOnly) { // actor is not replicated on this channel. continue; } Assert.IsFalse(actor.netTornOff); bool isRelevant; ObjectReplicator replicator; if (!CheckRelevancy(actor, out replicator, out isRelevant)) { Assert.IsFalse(actor.internal_NetTearOff); continue; } ReplicateObject(dt, actor, actor, replicator, actor.ownerConnectionID == _connection.id, isRelevant, ref packet); #if !PACKET_COMBINE packet = packet.Flush(connection); #endif objectRefs.Remove(actor.netIDHashCode); } ReplicateDependencies(ref packet); packet.Flush(connection); if (isTraveling) { ResetTimeoutForTravel(); isTraveling = false; GarbageCollect(); connection.SendReliable(NetMsgs.ServerFinishedTravel.New()); connection.driverConnection.blocking = false; } Perf.End(); }
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(); }
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 }