public unsafe void Assert_GotConnectionRequest(NetworkEndPoint from, bool accept = false)
        {
            int             length;
            NetworkEndPoint remote;

            m_LocalDataStream.Clear();
            Assert.True(
                IPCManager.Instance.PeekNext(Address, m_LocalDataStream.GetUnsafePtr(), out length, out remote) >=
                sizeof(UdpCHeader));
            m_LocalDataStream.WriteBytesWithUnsafePointer(length);

            UdpCHeader header    = new UdpCHeader();
            var        reader    = new DataStreamReader(m_LocalDataStream, 0, sizeof(UdpCHeader));
            var        readerCtx = default(DataStreamReader.Context);

            Assert.True(reader.IsCreated);
            reader.ReadBytes(ref readerCtx, header.Data, sizeof(UdpCHeader));
            Assert.True(header.Type == (int)UdpCProtocol.ConnectionRequest);

            Assert.True(remote.Family == NetworkFamily.IPC);
            //Assert.True(remote.ipc_handle == from.ipc_handle);
            Assert.True(remote.Port == from.Port);

            if (accept)
            {
                m_LocalDriver.ScheduleUpdate().Complete();
                var con = m_LocalDriver.Accept();
                ClientConnections.Add(con);
                Assert.True(con != default(NetworkConnection));
            }
        }
示例#2
0
        public IEnumerator ServerAndClient_PingPong_Successfully()
        {
            SetupServerAndClientAndConnectThem(0);

            //send data from client
            DataStreamWriter m_OutStream = new DataStreamWriter(16, Allocator.Persistent);

            m_OutStream.Clear();
            m_OutStream.Write(SharedConstants.ping);
            clientToServerConnection.Send(client_driver, m_OutStream);

            //handle sent data
            server_driver.ScheduleUpdate().Complete();
            ev = server_driver.PopEventForConnection(connectionToClient, out stream);
            Assert.IsTrue(ev == NetworkEvent.Type.Data, "Expected to get Type.Data");
            var readerCtx = default(DataStreamReader.Context);
            var msg       = stream.ReadBytesAsArray(ref readerCtx, stream.Length);

            if (msg.Length == SharedConstants.ping.Length)
            {
                for (var i = 0; i < msg.Length; i++)
                {
                    if (SharedConstants.ping[i] != msg[i])
                    {
                        Assert.Fail("Data reading error");
                    }
                }
            }

            client_driver.ScheduleUpdate().Complete();

            //send data from server
            m_OutStream.Clear();
            m_OutStream.Write(SharedConstants.pong);
            connectionToClient.Send(server_driver, m_OutStream);
            m_OutStream.Dispose();

            //handle sent data
            server_driver.ScheduleUpdate().Complete();
            client_driver.ScheduleUpdate().Complete();
            ev = clientToServerConnection.PopEvent(client_driver, out stream);
            Assert.IsTrue(ev == NetworkEvent.Type.Data, "Expected to get Type.Data");
            readerCtx = default(DataStreamReader.Context);
            msg       = stream.ReadBytesAsArray(ref readerCtx, stream.Length);
            if (msg.Length == SharedConstants.pong.Length)
            {
                for (var i = 0; i < msg.Length; i++)
                {
                    if (SharedConstants.pong[i] != msg[i])
                    {
                        Assert.Fail("Data reading error");
                    }
                }
            }

            DisconnectAndCleanup();
            yield return(null);
        }
示例#3
0
        public IEnumerator ServerAndClient_SendMessageWithMoreThenMaxLength_OverflowsIncomingDriverBuffer()
        {
            SetupServerAndClientAndConnectThem(0);

            //send data from client
            DataStreamWriter m_OutStream = new DataStreamWriter(1500, Allocator.Persistent);

            m_OutStream.Clear();
            int messageLength = 1401;

            byte[] messageToSend = new byte[messageLength];
            for (int i = 0; i < messageLength; i++)
            {
                messageToSend[i] = (byte)(33 + (i % 93));
            }

            m_OutStream.Write(messageToSend);
            clientToServerConnection.Send(client_driver, m_OutStream);
            LogAssert.Expect(LogType.Error, "Error on receive 10040");
            m_OutStream.Dispose();

            //handle sent data
            server_driver.ScheduleUpdate().Complete();
            client_driver.ScheduleUpdate().Complete();

            Assert.AreEqual(10040, server_driver.ReceiveErrorCode);

            DisconnectAndCleanup();
            yield return(null);
        }
        public void SendDataToRemoteEndPoint()
        {
            using (var host = new LocalDriverHelper(default(NetworkEndPoint)))
                using (var stream = new DataStreamWriter(64, Allocator.Persistent))
                {
                    host.Host();
                    var driver = new LocalNetworkDriver(new NetworkDataStreamParameter {
                        size = 64
                    });

                    // Need to be connected in order to be able to send a disconnect packet.
                    NetworkConnection connectionId = driver.Connect(host.Address);
                    Assert.True(connectionId != default(NetworkConnection));
                    driver.ScheduleUpdate().Complete();
                    var local = driver.LocalEndPoint();
                    host.Assert_GotConnectionRequest(local, true);

                    NetworkConnection con;
                    DataStreamReader  slice;
                    // Pump so we get the accept message back.
                    driver.ScheduleUpdate().Complete();
                    Assert.AreEqual(NetworkEvent.Type.Connect, driver.PopEvent(out con, out slice));

                    stream.Clear();
                    var data = Encoding.ASCII.GetBytes("data to send");
                    stream.Write(data);
                    driver.Send(connectionId, stream);
                    driver.ScheduleUpdate().Complete();

                    host.Assert_GotDataRequest(local, data);

                    driver.Dispose();
                }
        }
示例#5
0
        public IEnumerator ServerAndClient_SendMessageWithMaxLength_SentAndReceivedWithoutErrors()
        {
            SetupServerAndClientAndConnectThem(0);

            //send data from client
            DataStreamWriter m_OutStream = new DataStreamWriter(1500, Allocator.Persistent);

            m_OutStream.Clear();
            int messageLength = 1400;

            byte[] messageToSend = new byte[messageLength];
            for (int i = 0; i < messageLength; i++)
            {
                messageToSend[i] = (byte)(33 + (i % 93));
            }

            m_OutStream.Write(messageToSend);
            clientToServerConnection.Send(client_driver, m_OutStream);
            m_OutStream.Dispose();

            server_driver.ScheduleUpdate().Complete();
            ev = server_driver.PopEventForConnection(connectionToClient, out stream);
            Assert.IsTrue(ev == NetworkEvent.Type.Data, "Expected to get Type.Data");
            var readerCtx = default(DataStreamReader.Context);
            var msg       = stream.ReadBytesAsArray(ref readerCtx, stream.Length);

            Assert.IsTrue(msg.Length == messageLength, "Lenghts of sent and received messages are different");

            DisconnectAndCleanup();
            yield return(null);
        }
        public IEnumerator ServerAndClient_PingPong_Successfully()
        {
            SetupServerAndClientAndConnectThem(0);

            //send data from client
            DataStreamWriter m_OutStream = client_driver.BeginSend(clientToServerConnection);

            m_OutStream.Clear();
            m_OutStream.WriteBytes(new NativeArray <byte>(SharedConstants.ping, Allocator.Temp));
            client_driver.EndSend(m_OutStream);
            client_driver.ScheduleFlushSend(default).Complete();
        private void TestPipeline(int packetCount, NetworkPipeline serverPipe, int packetDelay = 100)
        {
            // Connect to server
            var clientToServer  = m_ClientDriver.Connect(m_ServerDriver.LocalEndPoint());
            var clientToServer2 = m_ClientDriver2.Connect(m_ServerDriver.LocalEndPoint());

            Assert.AreNotEqual(default(NetworkConnection), clientToServer);
            Assert.AreNotEqual(default(NetworkConnection), clientToServer2);
            m_ClientDriver.ScheduleUpdate().Complete();
            m_ClientDriver2.ScheduleUpdate().Complete();

            // Driver only updates time in update, so must read start time before update
            var startTime = Stopwatch.GetTimestamp() / TimeSpan.TicksPerMillisecond;

            // Handle incoming connection from client
            m_ServerDriver.ScheduleUpdate().Complete();
            var serverToClient = m_ServerDriver.Accept();

            Assert.AreNotEqual(default(NetworkConnection), serverToClient);
            var serverToClient2 = m_ServerDriver.Accept();

            Assert.AreNotEqual(default(NetworkConnection), serverToClient2);

            // Send given packetCount number of packets in a row in one update
            // Write 1's for packet 1, 2's for packet 2 and so on and verify they're received in same order
            var strm = new DataStreamWriter(64, Allocator.Temp);

            for (int i = 0; i < packetCount; i++)
            {
                strm.Clear();
                for (int j = 0; j < 16; j++)
                {
                    strm.Write((int)i + 1);
                }
                m_ServerDriver.Send(serverPipe, serverToClient, strm);
                m_ServerDriver.Send(serverPipe, serverToClient2, strm);
            }

            m_ServerDriver.ScheduleUpdate().Complete();

            // Receive incoming message from server
            m_ClientDriver.ScheduleUpdate().Complete();
            m_ClientDriver2.ScheduleUpdate().Complete();
            DataStreamReader readStrm;

            Assert.AreEqual(NetworkEvent.Type.Connect, clientToServer.PopEvent(m_ClientDriver, out readStrm));
            Assert.AreEqual(NetworkEvent.Type.Connect, clientToServer.PopEvent(m_ClientDriver2, out readStrm));

            ClientReceivePackets(m_ClientDriver, packetCount, clientToServer, startTime, packetDelay);
            ClientReceivePackets(m_ClientDriver2, packetCount, clientToServer2, startTime, packetDelay);
        }
示例#8
0
    public unsafe void SendPacket(ref SoakStatisticsPoint stats, ref SoakJobContext ctx)
    {
        var message = new SoakMessage
        {
            id   = ctx.FrameId,
            time = fixedTime,

            sequence = ctx.NextSequenceNumber++,
            length   = packetData.Length
        };

        streamWriter.Clear();

        streamWriter.WriteBytes(message.data, SoakMessage.HeaderLength);
        streamWriter.WriteBytes((byte *)packetData.GetUnsafeReadOnlyPtr(), packetData.Length);

        stats.SentBytes += connection[0].Send(driver, streamWriter);
        stats.SentPackets++;

        pendingSoaks[message.id % pendingSoaks.Length] = message;
    }
示例#9
0
        public IEnumerator ServerAndClient_SendMessageWithoutReadingIt_GivesErrorOnDriverUpdate()
        {
            SetupServerAndClientAndConnectThem(0);

            //send data from client
            DataStreamWriter m_OutStream = new DataStreamWriter(16, Allocator.Persistent);

            m_OutStream.Clear();
            m_OutStream.Write(SharedConstants.ping);
            clientToServerConnection.Send(client_driver, m_OutStream);
            m_OutStream.Dispose();

            server_driver.ScheduleUpdate().Complete();
            client_driver.ScheduleUpdate().Complete();

            LogAssert.Expect(LogType.Error, "Resetting event queue with pending events (Count=1, ConnectionID=0) Listening: 1");
            server_driver.ScheduleUpdate().Complete();

            DisconnectAndCleanup();
            yield return(null);
        }
示例#10
0
        public IEnumerator ServerAndClient_SendBigMessage_OverflowsIncomingDriverBuffer()
        {
            SetupServerAndClientAndConnectThem(8);

            //send data from client
            DataStreamWriter m_OutStream = new DataStreamWriter(16, Allocator.Persistent);

            m_OutStream.Clear();
            m_OutStream.Write(SharedConstants.ping);
            clientToServerConnection.Send(client_driver, m_OutStream);

            LogAssert.Expect(LogType.Error, "Error on receive 10040");
            m_OutStream.Dispose();

            //handle sent data
            server_driver.ScheduleUpdate().Complete();
            client_driver.ScheduleUpdate().Complete();

            Assert.AreEqual(10040, server_driver.ReceiveErrorCode);

            DisconnectAndCleanup();
            yield return(null);
        }
示例#11
0
            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);
            }
示例#12
0
        public void SendNetObjectsUpdate()
        {
            if (State == ServerState.Debug)
            {
                return;
            }
            if (State != ServerState.Started)
            {
                throw new InvalidOperationException("Cannot set NetObject update: Server not running");
            }

            Profiler.BeginSample("NetObject Update");
            NetObject[] netObjects = NetObjectManager.Instance.NetObjects;

            const int headerSizeInBytes = 8;
            var       streamWriter      = new DataStreamWriter(MaxBytesPerMessage, Allocator.Temp);
            var       objectWriter      = new DataStreamWriter(MaxBytesPerMessage - headerSizeInBytes, Allocator.Temp);
            var       objectIndex       = 0;

            // compose new message if objects left to send or serialize
            while (objectIndex < netObjects.Length || objectWriter.Length > 0)
            {
                // header
                streamWriter.Clear();
                streamWriter.WriteInt(Commands.UpdateNetObjects);
                DataStreamWriter objectCountWriter = streamWriter;
                streamWriter.WriteInt(0);

                // add items as long as they fit
                var objectsInMessage = 0;
                while (streamWriter.Length + objectWriter.Length <= MaxBytesPerMessage)
                {
                    if (objectWriter.Length > 0)
                    {
                        streamWriter.WriteBytes(objectWriter.AsNativeArray());
                        objectWriter.Clear();
                        objectsInMessage++;
                    }

                    // next object. Write if dirty
                    if (objectIndex < netObjects.Length)
                    {
                        NetObject netObject = netObjects[objectIndex++];
                        if (netObject.IsDirty)
                        {
                            WriteNetObject(netObject, ref objectWriter);
                        }
                    }
                    else
                    {
                        break;
                    }
                }

                objectCountWriter.WriteInt(objectsInMessage);

                // message complete. Send if payload exists
                if (objectsInMessage == 0)
                {
                    break;
                }
                for (var connectionIndex = 0; connectionIndex < _connections.Length; connectionIndex++)
                {
                    DataStreamWriter writer = _serverDriver.BeginSend(_reliablePipeline, _connections[connectionIndex]);
                    writer.WriteBytes(streamWriter.AsNativeArray());
                    _serverDriver.EndSend(writer);
                }
            }

            Profiler.EndSample();
        }
示例#13
0
        private void SendNetAssetUpdate(bool fullLoad, NativeList <NetworkConnection> connections)
        {
            if (State == ServerState.Debug)
            {
                return;
            }
            if (State != ServerState.Started)
            {
                throw new InvalidOperationException("Cannot send NetAsset update: Server not running");
            }
            Profiler.BeginSample("NetAsset Update");

            NetAsset[] netAssets         = NetAssetManager.Instance.GetAll();
            const int  headerSizeInBytes = 8;
            var        streamWriter      = new DataStreamWriter(MaxBytesPerMessage, Allocator.Temp);
            var        assetWriter       = new DataStreamWriter(MaxBytesPerMessage - headerSizeInBytes, Allocator.Temp);
            var        assetIndex        = 0;

            // compose new message if assets left to send or serialize
            while (assetIndex < netAssets.Length || assetWriter.Length > 0)
            {
                streamWriter.Clear();

                // write header
                streamWriter.WriteInt(Commands.UpdateNetAssets);
                DataStreamWriter netAssetCountWriter = streamWriter;
                streamWriter.WriteInt(0);

                // add assets as long as they fit
                var assetsInMessage = 0;
                while (streamWriter.Length + assetWriter.Length <= MaxBytesPerMessage)
                {
                    if (assetWriter.Length > 0)
                    {
                        streamWriter.WriteBytes(assetWriter.AsNativeArray());
                        assetWriter.Clear();
                        assetsInMessage++;
                    }

                    // next asset. Serialize if dirty
                    if (assetIndex < netAssets.Length)
                    {
                        NetAsset netAsset = netAssets[assetIndex++];
                        if (fullLoad || netAsset.IsDirty())
                        {
                            SerializeNetAsset(netAsset, ref assetWriter, fullLoad);
                        }
                    }
                    else
                    {
                        break;
                    }
                }

                netAssetCountWriter.WriteInt(assetsInMessage);

                // message complete. Send if payload exists
                if (assetsInMessage == 0)
                {
                    break;
                }
                for (var connectionIndex = 0; connectionIndex < connections.Length; connectionIndex++)
                {
                    DataStreamWriter writer = _serverDriver.BeginSend(_reliablePipeline, connections[connectionIndex]);
                    writer.WriteBytes(streamWriter.AsNativeArray());
                    _serverDriver.EndSend(writer);
                }
            }

            Profiler.EndSample();
        }
示例#14
0
        private void SendSpawnMessage(NetObject[] netObjects, NativeList <NetworkConnection> connections)
        {
            if (connections.Length == 0)
            {
                return;
            }
            AssertActive();
            const int headerSizeInBytes = 8;
            var       streamWriter      = new DataStreamWriter(MaxBytesPerMessage, Allocator.Temp);
            var       objectWriter      = new DataStreamWriter(MaxBytesPerMessage - headerSizeInBytes, Allocator.Temp);
            var       objectIndex       = 0;

            // compose new message if objects left to send or copy to message stream
            while (objectIndex < netObjects.Length || objectWriter.Length > 0)
            {
                streamWriter.Clear();

                // write header
                streamWriter.WriteInt(Commands.SpawnNetObjects);
                DataStreamWriter objectCountWriter = streamWriter;
                streamWriter.WriteInt(0);

                // copy data over to message stream and write to object stream
                var objectsInMessage = 0;
                while (streamWriter.Length + objectWriter.Length <= MaxBytesPerMessage)
                {
                    if (objectWriter.Length > 0)
                    {
                        streamWriter.WriteBytes(objectWriter.AsNativeArray());
                        objectWriter.Clear();
                        objectsInMessage++;
                    }

                    if (objectIndex < netObjects.Length)
                    {
                        NetObject netObject = netObjects[objectIndex++];
                        objectWriter.WriteInt(netObject.ID);
                        objectWriter.WriteUShort(netObject.PrefabIndex);
                        objectWriter.WriteInt(netObject.OwnerActorNumber);
                        objectWriter.WriteVector3(netObject.transform.position);
                        objectWriter.WriteQuaternion(netObject.transform.rotation);
                        objectWriter.WriteInt(netObject.gameObject.scene.buildIndex);
                        DataStreamWriter objectSizeWriter = objectWriter;
                        objectWriter.WriteInt(0);
                        int length = objectWriter.Length;
                        netObject.Serialize(ref objectWriter, true);
                        objectSizeWriter.WriteInt(objectWriter.Length - length);
                    }
                    else
                    {
                        break;
                    }
                }

                objectCountWriter.WriteInt(objectsInMessage);

                // message complete. Send if payload present
                if (objectsInMessage == 0)
                {
                    return;
                }
                for (var connectionIndex = 0; connectionIndex < connections.Length; connectionIndex++)
                {
                    DataStreamWriter writer = _serverDriver.BeginSend(_reliablePipeline, connections[connectionIndex]);
                    writer.WriteBytes(streamWriter.AsNativeArray());
                    _serverDriver.EndSend(writer);
                }
            }
        }
示例#15
0
        public void SendBatchedNetObjectsUpdate()
        {
            if (State == ClientState.Debug)
            {
                return;
            }
            if (State != ClientState.Connected)
            {
                Debug.LogWarning($"Cannot send messages in client state {State}");
                return;
            }

            if (IsHost)
            {
                return;
            }

            NetObject[] netObjects = NetObjectManager.Instance.NetObjects;

            const int headerSizeInBytes = 8;
            var       streamWriter      = new DataStreamWriter(MaxBytesPerMessage, Allocator.Temp);
            var       objectWriter      = new DataStreamWriter(MaxBytesPerMessage - headerSizeInBytes, Allocator.Temp);
            var       objectIndex       = 0;

            // compose new message if objects left to send or serialize
            while (objectIndex < netObjects.Length || objectWriter.Length > 0)
            {
                // header
                streamWriter.Clear();
                streamWriter.WriteInt(Commands.UpdateNetObjects);
                DataStreamWriter objectCountWriter = streamWriter;
                streamWriter.WriteInt(0);

                // add items as long as they fit
                var objectsInMessage = 0;
                while (streamWriter.Length + objectWriter.Length <= MaxBytesPerMessage)
                {
                    if (objectWriter.Length > 0)
                    {
                        streamWriter.WriteBytes(objectWriter.AsNativeArray());
                        objectWriter.Clear();
                        objectsInMessage++;
                    }

                    // next object. Write if dirty and controlled by this client
                    if (objectIndex < netObjects.Length)
                    {
                        NetObject netObject = netObjects[objectIndex++];
                        if (netObject.IsDirty && netObject.IsMine)
                        {
                            WriteNetObject(netObject, ref objectWriter);
                        }
                    }
                    else
                    {
                        break;
                    }
                }

                objectCountWriter.WriteInt(objectsInMessage);

                // message complete. Send if payload exists
                if (objectsInMessage > 0)
                {
                    DataStreamWriter writer = _clientDriver.BeginSend(_reliablePipeline, _clientToServerConnection);
                    writer.WriteBytes(streamWriter.AsNativeArray());
                    _clientDriver.EndSend(writer);
                    DataSent?.Invoke(writer.Length);
                }
            }
        }
        public void FillInternalBitStreamBuffer()
        {
            const int k_InternalBufferSize = 1000;
            const int k_PacketCount        = 21; // Exactly enough to fill the receive buffer + 1 too much
            const int k_PacketSize         = 50;

            using (var host = new LocalNetworkDriver(new NetworkDataStreamParameter {
                size = k_InternalBufferSize
            }))
                using (var client = new LocalNetworkDriver(new NetworkDataStreamParameter {
                    size = 64
                }))
                    using (var stream = new DataStreamWriter(64, Allocator.Persistent))
                    {
                        host.Bind(IPCManager.Instance.CreateEndPoint(Utilities.Random.String(32)));
                        host.Listen();

                        NetworkConnection connectionId = client.Connect(host.LocalEndPoint());

                        client.ScheduleUpdate().Complete();
                        host.ScheduleUpdate().Complete();

                        NetworkConnection poppedId;
                        DataStreamReader  reader;
                        host.Accept();

                        client.ScheduleUpdate().Complete();

                        var retval = client.PopEvent(out poppedId, out reader);
                        Assert.AreEqual(retval, NetworkEvent.Type.Connect);

                        var dataBlob = new Dictionary <int, byte[]>();
                        for (int i = 0; i < k_PacketCount; ++i)
                        {
                            // Scramble each packet contents so you can't match reading the same data twice as success
                            dataBlob.Add(i, Encoding.ASCII.GetBytes(Utilities.Random.String(k_PacketSize)));
                        }

                        for (int i = 0; i < k_PacketCount; ++i)
                        {
                            stream.Clear();
                            stream.Write(dataBlob[i]);
                            client.Send(connectionId, stream);
                        }

                        // Process the pending events
                        client.ScheduleUpdate().Complete();
                        host.ScheduleUpdate().Complete();

                        for (int i = 0; i < k_PacketCount; ++i)
                        {
                            retval = host.PopEvent(out poppedId, out reader);

                            if (i == k_PacketCount - 1)
                            {
                                Assert.AreEqual(retval, NetworkEvent.Type.Empty);
                                Assert.IsFalse(reader.IsCreated);
                                host.ScheduleUpdate().Complete();
                                retval = host.PopEvent(out poppedId, out reader);
                            }

                            Assert.AreEqual(retval, NetworkEvent.Type.Data);
                            Assert.AreEqual(k_PacketSize, reader.Length);

                            var readerCtx = default(DataStreamReader.Context);
                            for (int j = 0; j < k_PacketSize; ++j)
                            {
                                Assert.AreEqual(dataBlob[i][j], reader.ReadByte(ref readerCtx));
                            }
                        }
                    }
        }
示例#17
0
        protected override void OnUpdate()
        {
            if (!m_ConnectionWithoutSnapshotBufferGroup.IsEmptyIgnoreFilter)
            {
                using (var entities = m_ConnectionWithoutSnapshotBufferGroup.ToEntityArray(Allocator.TempJob))
                {
                    foreach (var entity in entities)
                    {
                        var buffer = EntityManager.AddBuffer <ClientSnapshotBuffer>(entity);
                        buffer.ResizeUninitialized(1200);
                        buffer.Clear();
                    }
                }
            }

            using (var deleteKeys = new NativeList <Entity>(8, Allocator.Temp))
            {
                foreach (var kvp in m_SerializeLookup)
                {
                    if (!EntityManager.Exists(kvp.Key))
                    {
                        deleteKeys.Add(kvp.Key);
                    }
                }

                foreach (var key in deleteKeys)
                {
                    m_SerializeLookup[key].Data.Dispose();
                    m_SerializeLookup.Remove(key);
                }
            }

            var connectionEntities           = m_ConnectionGroup.ToEntityArray(Allocator.TempJob);
            var networkStreamConnectionArray = m_ConnectionGroup.ToComponentDataArray <NetworkStreamConnection>(Allocator.TempJob);
            var ackComponentArray            = m_ConnectionGroup.ToComponentDataArray <NetworkSnapshotAckComponent>(Allocator.TempJob);

            foreach (var entity in connectionEntities)
            {
                if (m_SerializeLookup.ContainsKey(entity))
                {
                    continue;
                }

                m_SerializeLookup[entity] = new ReferencableSerializeClientData
                {
                    Data = new SerializeClientData(Allocator.Persistent)
                };
            }

            m_CreateSnapshotSystem.CreateSnapshot(m_ServerSimulationSystemGroup.ServerTick, m_SerializeLookup);

            var localTime = NetworkTimeSystem.TimestampMS;

            for (var ent = 0; ent < connectionEntities.Length; ent++)
            {
                var entity     = connectionEntities[ent];
                var connection = networkStreamConnectionArray[ent];
                var ack        = ackComponentArray[ent];

                var buffer = EntityManager.GetBuffer <ClientSnapshotBuffer>(entity);

                m_DataStream.Clear();
                m_DataStream.Write((byte)NetworkStreamProtocol.Snapshot);
                m_DataStream.Write(localTime);
                var returnTime = ack.LastReceivedRemoteTime;
                if (returnTime != 0)
                {
                    returnTime -= (localTime - ack.LastReceiveTimestamp);
                }
                m_DataStream.Write(returnTime);
                m_DataStream.Write(ack.ServerCommandAge);
                m_DataStream.Write(byte.MaxValue);
                m_DataStream.Write(m_ServerSimulationSystemGroup.ServerTick);

                Profiler.BeginSample("Compressing");
                var compressed       = UnsafeUtility.Malloc(LZ4Codec.MaximumOutputSize(buffer.Length), UnsafeUtility.AlignOf <byte>(), Allocator.Temp);
                var compressedLength = LZ4Codec.MaximumOutputSize(buffer.Length);
                {
                    var encoder = LZ4Level.L04_HC;                     // default encoder
                    //encoder = LZ4Level.L12_MAX;

                    var size = LZ4Codec.Encode((byte *)buffer.GetUnsafePtr(), buffer.Length, (byte *)compressed, compressedLength, encoder);
                    Profiler.EndSample();
                    m_DataStream.Write(size);
                    m_DataStream.Write(buffer.Length);

                    if (size > 1000)
                    {
                        Debug.Log($"s={size} b={buffer.Length}");
                    }

                    m_DataStream.WriteBytes((byte *)compressed, size);
                }
                UnsafeUtility.Free(compressed, Allocator.Temp);

                m_ReceiveSystem.Driver.Send(m_ReceiveSystem.ReliablePipeline, connection.Value, m_DataStream);
            }

            connectionEntities.Dispose();
            networkStreamConnectionArray.Dispose();
            ackComponentArray.Dispose();
        }
示例#18
0
            public void Execute()
            {
                DataStreamReader stream;

                NetworkEvent.Type cmd;

                //前フレームで解決できなかったbufferedからuncheckedに登録.
                if (!savedUncheckedReliableDataStream.IsCreated)
                {
                    stream = new DataStreamReader(savedUncheckedReliableDataStream, 0, savedUncheckedReliableDataStream.Length);
                    int offset = 0;
                    while (offset < savedUncheckedReliableDataStream.Length)
                    {
                        var    readerCtx = default(DataStreamReader.Context);
                        ushort length    = stream.ReadUShort(ref readerCtx);
                        if (0 < length && length <= savedUncheckedReliableDataStream.Length - offset - 2)
                        {
                            uncheckedreliableStreams.Add(
                                new DataStreamReader(savedUncheckedReliableDataStream, offset + 2, length));
                            offset += length + 2;
                        }
                        else
                        {
                            break;
                        }
                    }
                }

                while ((cmd = connection.PopEvent(driver, out stream)) != NetworkEvent.Type.Empty)
                {
                    if (cmd == NetworkEvent.Type.Connect)
                    {
                        flags[(int)FlagDef.IsConnected] = 1;
                        Debug.Log("Connect : " + connection.InternalId);
                    }
                    else if (cmd == NetworkEvent.Type.Disconnect)
                    {
                        flags[(int)FlagDef.IsDisconnected] = 1;
                        Debug.Log("Disconnect : " + connection.InternalId);
                    }
                    else if (cmd == NetworkEvent.Type.Data)
                    {
                        if (!stream.IsCreated)
                        {
                            continue;
                        }

                        var    readerCtx = default(DataStreamReader.Context);
                        byte   qosType   = stream.ReadByte(ref readerCtx);
                        ushort seqNum    = stream.ReadUShort(ref readerCtx);
                        ushort ackNum    = stream.ReadUShort(ref readerCtx);

                        //if (qosType != (byte)QosType.MeasureLatency) {
                        //	Debug.Log ("Recieve Data Len=" + stream.Length + ",QoS=" + qosType + ",Seq=" + seqNum + ",Ack=" + ackNum);
                        //}
                        //最初のregister packetはseqNumに

                        bool isInitialUpdate = flags[(int)FlagDef.IsNotInitialUpdate] == 0;

                        //ackNumの更新
                        if (seqNumbers[(int)SeqNumberDef.OtherAck] != ackNum)
                        {
                            seqNumbers[(int)SeqNumberDef.OtherAck] = ackNum;
                            //Debug.Log ("update OtherAck = " + ackNum + " first=" + isInitialUpdate);
                        }

                        switch ((QosType)qosType)
                        {
                        case QosType.MeasureLatency:
                            long currentUnixTime = System.DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
                            long otherUnixTime   = stream.ReadLong(ref readerCtx);
                            seqNumbers[(int)SeqNumberDef.Latency] = (ushort)(currentUnixTime - otherUnixTime);
                            break;

                        case QosType.Unreliable:
                            dataStreams.Add(stream);
                            break;

                        case QosType.Reliable:
                            int seqNumberDiff = (int)seqNum - seqNumbers[(int)SeqNumberDef.OtherSeq];
                            if (!isInitialUpdate && seqNumberDiff > 1)
                            {
                                //Debug.Log ("Reliable seqNumberDiff > 1 recieve");
                                //順番が入れ替わってるからバッファに貯める
                                if (seqNumberDiff - 2 < uncheckedreliableStreams.Length)
                                {
                                    if (uncheckedreliableStreams[seqNumberDiff - 2].IsCreated)
                                    {
                                        uncheckedreliableStreams[seqNumberDiff - 2] = stream;
                                    }
                                }
                                else
                                {
                                    uncheckedreliableStreams.Add(stream);
                                }
                            }
                            else if (isInitialUpdate || (seqNumberDiff == 1 || seqNumberDiff == -ushort.MaxValue))
                            {
                                flags[(int)FlagDef.IsNotInitialUpdate] = 1;
                                //次の順のパケットなら確定する
                                seqNumbers[(int)SeqNumberDef.OtherSeq] = seqNum;
                                //Debug.Log ("update OtherSeq = " + seqNumbers[(int)SeqNumberDef.OtherSeq] + " first=" + isInitialUpdate);
                                //AddChunksInDataStream (stream, ref readerCtx);
                                dataStreams.Add(stream);

                                //順番待ちのパケットを確定する
                                while (uncheckedreliableStreams.Length != 0)
                                {
                                    if (!uncheckedreliableStreams[0].IsCreated)
                                    {
                                        IncrementSequenceNumber(SeqNumberDef.OtherSeq);
                                        //Debug.Log ("update OtherSeq = " + seqNumbers[(int)SeqNumberDef.OtherSeq]);
                                        //AddChunksInDataStream (uncheckedreliableStreams[0], ref readerCtx);
                                        dataStreams.Add(uncheckedreliableStreams[0]);
                                        uncheckedreliableStreams.RemoveAtSwapBack(0);
                                    }
                                    else
                                    {
                                        break;
                                    }
                                }
                            }
                            else
                            {
                                //受信済みのSeqNumのパケットなら無視
                                //Debug.Log ("Reliable same recieve");
                            }
                            break;
                        }
                    }
                }

                //uncheckedreliableStreamsに残ったパケットはnetworkdriverから実態が消される前にコピーしておく
                unsafe {
                    //uncheckedreliableStreamsはsavedUncheckedReliableDataStreamに実態を持つ場合があるので
                    //直接savedUncheckedReliableDataStream書き込むと実態が消えてしまうのでtempまず書く
                    tempUncheckedReliableDataStream.Clear();
                    for (int i = 0; i < uncheckedreliableStreams.Length; i++)
                    {
                        int dataLength = uncheckedreliableStreams[i].Length;
                        if (tempUncheckedReliableDataStream.Capacity - tempUncheckedReliableDataStream.Length < dataLength + 2)
                        {
                            tempUncheckedReliableDataStream.Capacity *= 2;
                        }
                        byte *dataPtr = DataStreamUnsafeUtility.GetUnsafeReadOnlyPtr(uncheckedreliableStreams[i]);
                        tempUncheckedReliableDataStream.Write(dataLength);
                        tempUncheckedReliableDataStream.WriteBytes(dataPtr, dataLength);
                    }
                    savedUncheckedReliableDataStream.Clear();
                    if (savedUncheckedReliableDataStream.Capacity < tempUncheckedReliableDataStream.Capacity)
                    {
                        savedUncheckedReliableDataStream.Capacity *= tempUncheckedReliableDataStream.Capacity;
                    }
                    savedUncheckedReliableDataStream.WriteBytes(
                        tempUncheckedReliableDataStream.GetUnsafeReadOnlyPtr(), tempUncheckedReliableDataStream.Length);
                }

                //次に自分が送るパケットでどこまで受け取ったか伝える.
                seqNumbers[(int)SeqNumberDef.SelfAck] = seqNumbers[(int)SeqNumberDef.OtherSeq];
            }