static NetworkConnection ProcessSingleConnection(UdpNetworkDriver.Concurrent driver, NetworkConnection connection) { DataStreamReader strm; NetworkEvent.Type cmd; // Pop all events for the connection while ((cmd = driver.PopEventForConnection(connection, out strm)) != NetworkEvent.Type.Empty) { if (cmd == NetworkEvent.Type.Data) { // For ping requests we reply with a pong message // A DataStreamReader.Context is required to keep track of current read position since // DataStreamReader is immutable var readerCtx = default(DataStreamReader.Context); int id = strm.ReadInt(ref readerCtx); // Create a temporary DataStreamWriter to keep our serialized pong message var pongData = new DataStreamWriter(4, Allocator.Temp); pongData.Write(id); // Send the pong message with the same id as the ping driver.Send(NetworkPipeline.Null, connection, pongData); } else if (cmd == NetworkEvent.Type.Disconnect) { // When disconnected we make sure the connection return false to IsCreated so the next frames // DriverUpdateJob will remove it return(default(NetworkConnection)); } } return(connection); }
public void Execute(int index) { DataStreamReader stream; if (!connections[index].IsCreated) { Assert.IsTrue(true); } NetworkEvent.Type cmd; while ((cmd = driver.PopEventForConnection(connections[index], out stream)) != NetworkEvent.Type.Empty) { if (cmd == NetworkEvent.Type.Data) { var readerCtx = default(DataStreamReader.Context); uint number = stream.ReadUInt(ref readerCtx); Debug.Log("Got " + number + " from the Client adding + 2 to it."); number += 2; using (var writer = new DataStreamWriter(4, Allocator.Temp)) { writer.Write(number); driver.Send(pipeline, connections[index], writer); } } else if (cmd == NetworkEvent.Type.Disconnect) { Debug.Log("Client disconnected from server"); connections[index] = default(NetworkConnection); } } }
public unsafe void Execute(Entity entity, int index, ref NetworkStreamConnection connection) { if (!connection.Value.IsCreated) { return; } var buffer = rpcBufferFromEntity[entity]; if (buffer.Length > 0) { DataStreamWriter tmp = new DataStreamWriter(buffer.Length, Allocator.Temp); tmp.WriteBytes((byte *)buffer.GetUnsafePtr(), buffer.Length); driver.Send(reliablePipeline, connection.Value, tmp); buffer.Clear(); } var cmdBuffer = cmdBufferFromEntity[entity]; if (cmdBuffer.Length > 0) { DataStreamWriter tmp = new DataStreamWriter(cmdBuffer.Length, Allocator.Temp); tmp.WriteBytes((byte *)cmdBuffer.GetUnsafePtr(), cmdBuffer.Length); driver.Send(unreliablePipeline, connection.Value, tmp); cmdBuffer.Clear(); } var snapBuffer = snapshotBufferFromEntity[entity]; if (snapBuffer.Length > 0) { DataStreamWriter tmp = new DataStreamWriter(snapBuffer.Length, Allocator.Temp); tmp.WriteBytes((byte *)snapBuffer.GetUnsafePtr(), snapBuffer.Length); driver.Send(unreliablePipeline, connection.Value, tmp); snapBuffer.Clear(); } }
public unsafe void Execute(Entity entity, int index, DynamicBuffer <TBufferElementData> buffer, ref NetworkConnection connection) { //if (!connection.value.IsCreated) // return; if (buffer.Length > 0) { driver.Send(pipeline, connection.value, (System.IntPtr)buffer.GetUnsafePtr(), buffer.Length); buffer.Clear(); /*DataStreamWriter tmp = new DataStreamWriter(buffer.Length, Allocator.Temp); * tmp.WriteBytes((byte*)buffer.GetUnsafePtr(), buffer.Length); * driver.Send(unreliablePipeline, connection.Value, tmp); * buffer.Clear();*/ } }
public void Execute([ReadOnly] ref NetworkStreamConnection connection, [ReadOnly] ref NetworkSnapshotAckComponent ack, [ReadOnly] ref CommandTargetComponent state) { if (typeof(TCommandData) == typeof(NullCommandData) && state.targetEntity != Entity.Null) { return; } if (typeof(TCommandData) != typeof(NullCommandData) && !inputFromEntity.Exists(state.targetEntity)) { return; } DataStreamWriter writer = new DataStreamWriter(1200, Allocator.Temp); writer.Write((byte)NetworkStreamProtocol.Command); writer.Write(ack.LastReceivedSnapshotByLocal); writer.Write(ack.ReceivedSnapshotByLocalMask); writer.Write(localTime); uint returnTime = ack.LastReceivedRemoteTime; if (returnTime != 0) { returnTime -= (localTime - ack.LastReceiveTimestamp); } writer.Write(returnTime); writer.Write(inputTargetTick); if (state.targetEntity != Entity.Null) { var input = inputFromEntity[state.targetEntity]; TCommandData baselineInputData; input.GetDataAtTick(inputTargetTick, out baselineInputData); baselineInputData.Serialize(writer); for (uint inputIndex = 1; inputIndex < k_InputBufferSendSize; ++inputIndex) { TCommandData inputData; input.GetDataAtTick(inputTargetTick - inputIndex, out inputData); inputData.Serialize(writer, baselineInputData, compressionModel); } writer.Flush(); } #if UNITY_EDITOR || DEVELOPMENT_BUILD netStats[0] = inputTargetTick; netStats[1] = (uint)writer.Length; #endif driver.Send(unreliablePipeline, connection.Value, writer); }
public void Execute(int i) { SoakMessage inbound = default(SoakMessage); SoakMessage outbound = default(SoakMessage); if (connections[i].Connection.IsCreated) { var ctx = connections[i]; DataStreamReader strm; NetworkEvent.Type cmd; bool close = false; while ((cmd = driver.PopEventForConnection(ctx.Connection, out strm)) != NetworkEvent.Type.Empty) { if (cmd == NetworkEvent.Type.Data) { var readerCtx = default(DataStreamReader.Context); unsafe { strm.ReadBytes(ref readerCtx, inbound.data, strm.Length); Assert.AreEqual(strm.Length, inbound.length + SoakMessage.HeaderLength); outbound.id = inbound.id; outbound.sequence = ctx.NextSequenceId++; var soakData = new DataStreamWriter(SoakMessage.HeaderLength, Allocator.Temp); soakData.WriteBytes(outbound.data, SoakMessage.HeaderLength); driver.Send(pipeline, connections[i].Connection, soakData); } } else if (cmd == NetworkEvent.Type.Disconnect) { close = true; } } if (close) { ctx.Connection = default(NetworkConnection); ctx.NextSequenceId = -1; } connections[i] = ctx; } }
public void Execute(ref PingServerConnectionComponentData connection) { DataStreamReader strm; NetworkEvent.Type cmd; while ((cmd = driver.PopEventForConnection(connection.connection, out strm)) != NetworkEvent.Type.Empty) { if (cmd == NetworkEvent.Type.Data) { var readerCtx = default(DataStreamReader.Context); int id = strm.ReadInt(ref readerCtx); var pongData = new DataStreamWriter(4, Allocator.Temp); pongData.Write(id); driver.Send(NetworkPipeline.Null, connection.connection, pongData); } else if (cmd == NetworkEvent.Type.Disconnect) { connection = new PingServerConnectionComponentData { connection = default(NetworkConnection) }; } } }
public unsafe void Execute(Entity entity, int index, [ReadOnly] ref CommandTargetComponent state) { DataStreamWriter writer = new DataStreamWriter(128, Allocator.Temp); var ack = ackSnapshot[entity]; writer.Write((byte)NetworkStreamProtocol.Command); writer.Write(ack.LastReceivedSnapshotByLocal); writer.Write(ack.ReceivedSnapshotByLocalMask); writer.Write(localTime); writer.Write(ack.LastReceivedRemoteTime - (localTime - ack.LastReceiveTimestamp)); if (state.targetEntity != Entity.Null && inputFromEntity.Exists(state.targetEntity)) { var input = inputFromEntity[state.targetEntity]; TCommandData inputData; if (input.GetDataAtTick(inputTargetTick, out inputData) && inputData.Tick == inputTargetTick) { writer.Write(inputTargetTick); inputData.Serialize(writer); } } driver.Send(unreliablePipeline, connectionFromEntity[entity].Value, writer); }
public void Execute(int index) { DataStreamReader stream; if (!connections[index].IsCreated) { Assert.IsTrue(true); } NetworkEvent.Type cmd; while ((cmd = driver.PopEventForConnection(connections[index], out stream)) != NetworkEvent.Type.Empty) { if (cmd == NetworkEvent.Type.Data) { var readerCtx = default(DataStreamReader.Context); byte[] value = stream.ReadBytesAsArray(ref readerCtx, stream.Length); CustomType ct = cts.DeSerialize(value); Debug.Log("Got " + ct.val + " from the Client adding + 2 to it."); ct.val += 2; var buff = cts.Serialize(ct); using (var writer = new DataStreamWriter(buff.Length, Allocator.Temp)) { writer.Write(buff); driver.Send(NetworkPipeline.Null, connections[index], writer); } } else if (cmd == NetworkEvent.Type.Disconnect) { Debug.Log("Client disconnected from server"); connections[index] = default(NetworkConnection); } } }
public unsafe void Execute(Entity entity, int index, [ReadOnly] ref CommandTargetComponent state) { DataStreamWriter writer = new DataStreamWriter(128, Allocator.Temp); var ack = ackSnapshot[entity]; writer.Write((byte)NetworkStreamProtocol.Command); writer.Write(ack.LastReceivedSnapshotByLocal); writer.Write(ack.ReceivedSnapshotByLocalMask); writer.Write(localTime); // writer.Write(ack.LastReceivedRemoteTime - (localTime - ack.LastReceiveTimestamp)); // TODO: LZ: // to be confirmed // we should send "t0 + (T1 - T0)", but not "t0 - (T1 - T0)" // // because: // RTT should equals to : (t1 - t0) - (T1 - T0) = t1 - [t0 + (T1 - T0)] // t0: A send time // ack.LastReceivedRemoteTime // T0: B receive time // ack.LastReceiveTimestamp // T1: B send time // localTime // t1: A receive time writer.Write(ack.LastReceivedRemoteTime + (localTime - ack.LastReceiveTimestamp)); if (state.targetEntity != Entity.Null && inputFromEntity.Exists(state.targetEntity)) { var input = inputFromEntity[state.targetEntity]; TCommandData inputData; if (input.GetDataAtTick(inputTargetTick, out inputData) && inputData.Tick == inputTargetTick) { writer.Write(inputTargetTick); inputData.Serialize(writer); } } driver.Send(unreliablePipeline, connectionFromEntity[entity].Value, writer); }
public unsafe void Execute() { var snapshotAck = ackFromEntity[connectionEntity]; var ackTick = snapshotAck.LastReceivedSnapshotByRemote; DataStreamWriter dataStream = new DataStreamWriter(2048, Allocator.Temp); dataStream.Clear(); dataStream.Write((byte)NetworkStreamProtocol.Snapshot); dataStream.Write(localTime); // dataStream.Write(snapshotAck.LastReceivedRemoteTime - (localTime - snapshotAck.LastReceiveTimestamp)); // TODO: LZ: // to be confirmed // we should send "t0 + (T1 - T0)", but not "t0 - (T1 - T0)" // // because: // RTT should equals to : (t1 - t0) - (T1 - T0) = t1 - [t0 + (T1 - T0)] // t0: A send time // snapshotAck.LastReceivedRemoteTime // T0: B receive time // snapshotAck.LastReceiveTimestamp // T1: B send time // localTime // t1: A receive time dataStream.Write(snapshotAck.LastReceivedRemoteTime + (localTime - snapshotAck.LastReceiveTimestamp)); dataStream.Write(currentTick); int entitySize = UnsafeUtility.SizeOf <Entity>(); var despawnLenWriter = dataStream.Write((uint)0); var updateLenWriter = dataStream.Write((uint)0); uint despawnLen = 0; // TODO: if not all despawns fit, sort them based on age and maybe time since last send // TODO: only resend despawn on nack // FIXME: the TargetPacketSize cannot be used since CleanupGhostJob relies on all ghosts being sent every frame for (var chunk = 0; chunk < despawnChunks.Length /*&& dataStream.Length < TargetPacketSize*/; ++chunk) { var entities = despawnChunks[chunk].GetNativeArray(entityType); var ghosts = despawnChunks[chunk].GetNativeArray(ghostSystemStateType); for (var ent = 0; ent < entities.Length /*&& dataStream.Length < TargetPacketSize*/; ++ent) { if (ackTick == 0 || SequenceHelpers.IsNewer(ghosts[ent].despawnTick, ackTick)) { dataStream.WritePackedUInt((uint)ghosts[ent].ghostId, compressionModel); ++despawnLen; } } } uint updateLen = 0; var serialChunks = new NativeList <PrioChunk>(ghostChunks.Length + serialSpawnChunks.Length, Allocator.Temp); serialChunks.AddRange(serialSpawnChunks); var existingChunks = new NativeHashMap <ArchetypeChunk, int>(ghostChunks.Length, Allocator.Temp); // TODO: LZ: // temp hack, fix me int maxCount = serialSpawnChunks.Length; for (int chunk = 0; chunk < ghostChunks.Length; ++chunk) { SerializationState chunkState; var addNew = !chunkSerializationData.TryGetValue(ghostChunks[chunk], out chunkState); // FIXME: should be using chunk sequence number instead of this hack if (!addNew && chunkState.arch != ghostChunks[chunk].Archetype) { UnsafeUtility.Free(chunkState.snapshotData, Allocator.Persistent); chunkSerializationData.Remove(ghostChunks[chunk]); addNew = true; } if (addNew) { chunkState.lastUpdate = currentTick - 1; chunkState.startIndex = 0; chunkState.ghostType = serializers.FindSerializer(ghostChunks[chunk].Archetype); chunkState.arch = ghostChunks[chunk].Archetype; chunkState.snapshotWriteIndex = 0; int serializerDataSize = serializers.GetSnapshotSize(chunkState.ghostType); chunkState.snapshotData = (byte *)UnsafeUtility.Malloc(UnsafeUtility.SizeOf <int>() * GhostSystemConstants.SnapshotHistorySize + GhostSystemConstants.SnapshotHistorySize * ghostChunks[chunk].Capacity * (UnsafeUtility.SizeOf <Entity>() + serializerDataSize), 16, Allocator.Persistent); // Just clear snapshot index UnsafeUtility.MemClear(chunkState.snapshotData, UnsafeUtility.SizeOf <int>() * GhostSystemConstants.SnapshotHistorySize); chunkSerializationData.TryAdd(ghostChunks[chunk], chunkState); } existingChunks.TryAdd(ghostChunks[chunk], 1); // FIXME: only if modified or force sync var ghostType = chunkState.ghostType; var pc = new PrioChunk { chunk = ghostChunks[chunk], ghostState = null, priority = serializers.CalculateImportance(ghostType, ghostChunks[chunk]) * (int)(currentTick - chunkState.lastUpdate), startIndex = chunkState.startIndex, ghostType = ghostType }; serialChunks.Add(pc); if (ghostChunks[chunk].Count > maxCount) { maxCount = ghostChunks[chunk].Count; } } var oldChunks = chunkSerializationData.GetKeyArray(Allocator.Temp); for (int i = 0; i < oldChunks.Length; ++i) { int val; if (!existingChunks.TryGetValue(oldChunks[i], out val)) { SerializationState chunkState; chunkSerializationData.TryGetValue(oldChunks[i], out chunkState); UnsafeUtility.Free(chunkState.snapshotData, Allocator.Persistent); chunkSerializationData.Remove(oldChunks[i]); } } NativeArray <PrioChunk> serialChunkArray = serialChunks; serialChunkArray.Sort(); var availableBaselines = new NativeList <SnapshotBaseline>(GhostSystemConstants.SnapshotHistorySize, Allocator.Temp); var baselinePerEntity = new NativeArray <int>(maxCount * 3, Allocator.Temp); for (int pc = 0; pc < serialChunks.Length && dataStream.Length < TargetPacketSize; ++pc) { var chunk = serialChunks[pc].chunk; var ghostType = serialChunks[pc].ghostType; Entity * currentSnapshotEntity = null; byte * currentSnapshotData = null; SerializationState chunkState; int dataSize = 0; availableBaselines.Clear(); if (chunkSerializationData.TryGetValue(chunk, out chunkState)) { dataSize = serializers.GetSnapshotSize(chunkState.ghostType); uint *snapshotIndex = (uint *)chunkState.snapshotData; snapshotIndex[chunkState.snapshotWriteIndex] = currentTick; int baseline = (GhostSystemConstants.SnapshotHistorySize + chunkState.snapshotWriteIndex - 1) % GhostSystemConstants.SnapshotHistorySize; while (baseline != chunkState.snapshotWriteIndex) { if (snapshotAck.IsReceivedByRemote(snapshotIndex[baseline])) { byte *dataBase = chunkState.snapshotData + UnsafeUtility.SizeOf <int>() * GhostSystemConstants.SnapshotHistorySize + baseline * (dataSize + entitySize) * chunk.Capacity; availableBaselines.Add(new SnapshotBaseline { tick = snapshotIndex[baseline], snapshot = dataBase + entitySize * chunk.Capacity, entity = (Entity *)(dataBase) }); } baseline = (GhostSystemConstants.SnapshotHistorySize + baseline - 1) % GhostSystemConstants.SnapshotHistorySize; } // Find the acked snapshot to delta against, setup pointer to current and previous entity* and data* // Remember to bump writeIndex when done currentSnapshotData = chunkState.snapshotData + UnsafeUtility.SizeOf <int>() * GhostSystemConstants.SnapshotHistorySize; currentSnapshotData += chunkState.snapshotWriteIndex * (dataSize + entitySize) * chunk.Capacity; currentSnapshotEntity = (Entity *)currentSnapshotData; currentSnapshotData += entitySize * chunk.Capacity; } var ghosts = serialChunks[pc].ghostState; if (ghosts == null) { ghosts = (GhostSystemStateComponent *)chunk.GetNativeArray(ghostSystemStateType).GetUnsafeReadOnlyPtr(); } var ghostEntities = chunk.GetNativeArray(entityType); int ent; if (serialChunks[pc].startIndex < chunk.Count) { dataStream.WritePackedUInt((uint)ghostType, compressionModel); dataStream.WritePackedUInt((uint)(chunk.Count - serialChunks[pc].startIndex), compressionModel); } // First figure out the baselines to use per entity so they can be sent as baseline + maxCount instead of one per entity int targetBaselines = serializers.WantsPredictionDelta(ghostType) ? 3 : 1; for (ent = serialChunks[pc].startIndex; ent < chunk.Count; ++ent) { int foundBaselines = 0; for (int baseline = 0; baseline < availableBaselines.Length; ++baseline) { if (availableBaselines[baseline].entity[ent] == ghostEntities[ent]) { baselinePerEntity[ent * 3 + foundBaselines] = baseline; ++foundBaselines; if (foundBaselines == targetBaselines) { break; } } // Only way an entity can be missing from a snapshot but be available in an older is if last snapshot was partial else if (availableBaselines[baseline].entity[ent] != Entity.Null) { break; } } if (foundBaselines == 2) { foundBaselines = 1; } while (foundBaselines < 3) { baselinePerEntity[ent * 3 + foundBaselines] = -1; ++foundBaselines; } } ent = serializers.Serialize(ghostType, chunk, serialChunks[pc].startIndex, currentTick, currentSnapshotEntity, currentSnapshotData, ghosts, ghostEntities, baselinePerEntity, availableBaselines, dataStream, compressionModel); updateLen += (uint)(ent - serialChunks[pc].startIndex); // Spawn chunks are temporary and should not be added to the state data cache if (serialChunks[pc].ghostState == null) { // Only append chunks which contain data if (ent > serialChunks[pc].startIndex) { if (serialChunks[pc].startIndex > 0) { UnsafeUtility.MemClear(currentSnapshotEntity, entitySize * serialChunks[pc].startIndex); } if (ent < chunk.Capacity) { UnsafeUtility.MemClear(currentSnapshotEntity + ent, entitySize * (chunk.Capacity - ent)); } chunkState.snapshotWriteIndex = (chunkState.snapshotWriteIndex + 1) % GhostSystemConstants.SnapshotHistorySize; } if (ent >= chunk.Count) { chunkState.lastUpdate = currentTick; chunkState.startIndex = 0; } else { // TODO: should this always be run or should partial chunks only be allowed for the highest priority chunk? //if (pc == 0) chunkState.startIndex = ent; } chunkSerializationData.Remove(chunk); chunkSerializationData.TryAdd(chunk, chunkState); } } dataStream.Flush(); despawnLenWriter.Update(despawnLen); updateLenWriter.Update(updateLen); driver.Send(unreliablePipeline, connectionFromEntity[connectionEntity].Value, dataStream); }
public void Execute(Entity entity, int index, ref NetworkServerConnection serverConnection) { DataStreamReader stream; NetworkEvent.Type command; while ((command = driver.PopEventForConnection(serverConnection.connection, out stream)) != NetworkEvent.Type.Empty) { if (command == NetworkEvent.Type.Data) { /* * Structure of a message to be sent over the server * [size of message, not including this part, sizeof(int)][command type sizeof(int)][other data] */ Debug.Log("data command on server"); DataStreamReader.Context readerCtx = default(DataStreamReader.Context); byte[] lengthOfDataAsBytes = stream.ReadBytesAsArray(ref readerCtx, sizeof(int)); if (BitConverter.IsLittleEndian) { Array.Reverse(lengthOfDataAsBytes); } int lengthOfData = BitConverter.ToInt32(lengthOfDataAsBytes, 0); byte[] dataRead = stream.ReadBytesAsArray(ref readerCtx, lengthOfData); byte[] cmdTypeRead = new byte[sizeof(int)]; Buffer.BlockCopy(dataRead, 0, cmdTypeRead, 0, sizeof(int)); if (BitConverter.IsLittleEndian) { Array.Reverse(cmdTypeRead); } int commandType = BitConverter.ToInt32(cmdTypeRead, 0); Debug.Log("command type received " + commandType); if (commandType == CommandType.SpawnNewPlayer) { int networkId = id[0]; byte[] cmdTypeAsBytes = BitConverter.GetBytes(CommandType.SpawnNewPlayer); byte[] idAsBytes = BitConverter.GetBytes(networkId); if (BitConverter.IsLittleEndian) { Array.Reverse(cmdTypeAsBytes); Array.Reverse(idAsBytes); } byte[] result = NetworkingUtils.CombineBytes(cmdTypeAsBytes, idAsBytes); int lengthOfMsg = result.Length * sizeof(byte); // in bytes, one int, just for the command type and the id byte[] lengthAsBytes = BitConverter.GetBytes(lengthOfMsg); if (BitConverter.IsLittleEndian) { Array.Reverse(lengthAsBytes); } result = NetworkingUtils.CombineBytes(lengthAsBytes, result); DataStreamWriter data = new DataStreamWriter(sizeof(byte) * result.Length, Allocator.Temp); data.Write(result); id[0] += 1; driver.Send(NetworkPipeline.Null, serverConnection.connection, data); commandBuffer.SetComponent(index, entity, new NetworkServerConnection { networkId = networkId }); } } else if (command == NetworkEvent.Type.Disconnect) { commandBuffer.DestroyEntity(index, entity); } } }
public unsafe void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex) { var entities = chunk.GetNativeArray(entityType); var rpcInBuffer = chunk.GetBufferAccessor(inBufferType); var rpcOutBuffer = chunk.GetBufferAccessor(outBufferType); var connections = chunk.GetNativeArray(connectionType); for (int i = 0; i < rpcInBuffer.Length; ++i) { if (driver.GetConnectionState(connections[i].Value) != NetworkConnection.State.Connected) { continue; } var dynArray = rpcInBuffer[i]; var reader = DataStreamUnsafeUtility.CreateReaderFromExistingData((byte *)dynArray.GetUnsafePtr(), dynArray.Length); var parameters = new RpcExecutor.Parameters { Reader = reader, ReaderContext = default(DataStreamReader.Context), CommandBuffer = commandBuffer, Connection = entities[i], JobIndex = chunkIndex }; while (reader.GetBytesRead(ref parameters.ReaderContext) < reader.Length) { var rpcIndex = reader.ReadUShort(ref parameters.ReaderContext); if (rpcIndex == ushort.MaxValue) { // Special value for NetworkProtocolVersion var netCodeVersion = reader.ReadInt(ref parameters.ReaderContext); var gameVersion = reader.ReadInt(ref parameters.ReaderContext); var rpcVersion = reader.ReadULong(ref parameters.ReaderContext); if (netCodeVersion != protocolVersion.NetCodeVersion || gameVersion != protocolVersion.GameVersion || rpcVersion != protocolVersion.RpcCollectionVersion) { commandBuffer.AddComponent(chunkIndex, entities[i], new NetworkStreamRequestDisconnect { Reason = NetworkStreamDisconnectReason.BadProtocolVersion }); #if ENABLE_UNITY_COLLECTIONS_CHECKS throw new InvalidOperationException("Network protocol mismatch"); #else return; #endif } } else if (rpcIndex >= execute.Length) { #if ENABLE_UNITY_COLLECTIONS_CHECKS throw new InvalidOperationException("Received an invalid RPC"); #else return; #endif } else { execute[rpcIndex].Execute.Ptr.Invoke(ref parameters); } } dynArray.Clear(); var sendBuffer = rpcOutBuffer[i]; if (sendBuffer.Length > 0) { DataStreamWriter tmp = new DataStreamWriter(sendBuffer.Length, Allocator.Temp); tmp.WriteBytes((byte *)sendBuffer.GetUnsafePtr(), sendBuffer.Length); driver.Send(reliablePipeline, connections[i].Value, tmp); sendBuffer.Clear(); } } }
public void Execute(Entity entity, int index, ref NetworkClientConnection clientConnection) { if (!serverEndPoint.IsValid) { // TODO: disconnect if the server is not running on the end point commandBuffer.DestroyEntity(index, entity); } else { DataStreamReader stream; NetworkEvent.Type command; while ((command = driver.PopEventForConnection(clientConnection.connection, out stream)) != NetworkEvent.Type.Empty) { if (command == NetworkEvent.Type.Connect) { int lengthOfMsg = sizeof(int); // in bytes, one int, just for the command type, not including the length integer itself byte[] lengthAsBytes = BitConverter.GetBytes(lengthOfMsg); byte[] cmdTypeAsBytes = BitConverter.GetBytes(CommandType.SpawnNewPlayer); if (BitConverter.IsLittleEndian) { Array.Reverse(lengthAsBytes); Array.Reverse(cmdTypeAsBytes); } byte[] result = NetworkingUtils.CombineBytes(lengthAsBytes, cmdTypeAsBytes); DataStreamWriter data = new DataStreamWriter(sizeof(byte) * result.Length, Allocator.Temp); data.Write(result); Debug.Log("size of result " + sizeof(byte) * result.Length); Debug.Log("Sending confirmation of connection to server"); driver.Send(NetworkPipeline.Null, clientConnection.connection, data); } else if (command == NetworkEvent.Type.Data) { /* * Structure of a message to be sent over the server * [size of message, not including this part, sizeof(int)][command type sizeof(int)][other data] */ DataStreamReader.Context readerCtx = default(DataStreamReader.Context); byte[] lengthOfDataAsBytes = stream.ReadBytesAsArray(ref readerCtx, sizeof(int)); if (BitConverter.IsLittleEndian) { Array.Reverse(lengthOfDataAsBytes); } int lengthOfData = BitConverter.ToInt32(lengthOfDataAsBytes, 0); byte[] dataRead = stream.ReadBytesAsArray(ref readerCtx, lengthOfData); byte[] cmdTypeRead = new byte[sizeof(int)]; Buffer.BlockCopy(dataRead, 0, cmdTypeRead, 0, sizeof(int)); if (BitConverter.IsLittleEndian) { Array.Reverse(cmdTypeRead); } int commandType = BitConverter.ToInt32(cmdTypeRead, 0); if (commandType == CommandType.SpawnNewPlayer) { byte[] idAsBytes = new byte[sizeof(int)]; Buffer.BlockCopy(dataRead, sizeof(int), idAsBytes, 0, sizeof(int)); if (BitConverter.IsLittleEndian) { Array.Reverse(idAsBytes); } int id = BitConverter.ToInt32(idAsBytes, 0); Debug.Log("player id from server " + id); commandBuffer.SetComponent(index, entity, new NetworkClientConnection { networkId = id }); } } else if (command == NetworkEvent.Type.Disconnect) { commandBuffer.DestroyEntity(index, entity); } } } }