예제 #1
0
    public unsafe static NetworkEvent Serialize(ushort typeId, bool reliable, Dictionary <ushort, NetworkEventType> eventTypes, NetworkEventGenerator generator)
    {
        bool             generateSchema = false;
        NetworkEventType type;

        if (!eventTypes.TryGetValue(typeId, out type))
        {
            generateSchema = true;
            type           = new NetworkEventType()
            {
                typeId = typeId, schema = new NetworkSchema(NetworkConfig.firstEventTypeSchemaId + typeId)
            };
            eventTypes.Add(typeId, type);
        }

        var result = Create(type, reliable);

        result.sequence = ++s_Sequence;
        if (NetworkConfig.netDebug.IntValue > 0)
            GameDebug.Log("Serializing event " + ((GameNetworkEvents.EventType)result.type.typeId) + " in seq no: " + result.sequence);

        fixed(uint *data = result.data)
        {
            NetworkWriter writer = new NetworkWriter(data, result.data.Length, type.schema, generateSchema);

            generator(ref writer);
            writer.Flush();
        }

        return(result);
    }
예제 #2
0
        private BinaryWriter CreateOutputWriter()
        {
            try
            {
                string filePath = GenerateNewOutputFile();
                if (string.IsNullOrEmpty(filePath))
                {
                    Console.WriteLine($"Unable to generate a numbered file name using the prefix: {OutputPrefix}. Try cleaning up the output directory.");
                    return(null);
                }
                Console.WriteLine($"Recording to: {filePath}");

                Stream     stream     = null;
                FileStream fileStream = new FileStream(filePath, FileMode.Create);
                stream = fileStream;

                // Write the recording header uncompressed to the file.
                // We'll rewind here later and update the frame count.
                // Write to a memory stream to prevent corruption of the file stream when we wrap it
                // in a GZipStream.
                MemoryStream headerStream = new MemoryStream(512);
                BinaryWriter writer       = new NetworkWriter(headerStream);
                WriteRecordingHeader(writer);
                writer.Flush();
                byte[] headerBytes = headerStream.ToArray();

                // Copy header to the file.
                fileStream.Write(headerBytes, 0, headerBytes.Length);
                // Dispose of the temporary objects.
                headerBytes  = null;
                writer       = null;
                headerStream = null;

                switch (DecodeMode)
                {
                case Mode.CollateAndCompress:
                    stream = new CollationStream(fileStream, true);
                    break;

                case Mode.CollateOnly:
                    stream = new CollationStream(fileStream, false);
                    break;

                case Mode.FileCompression:
                    stream = new GZipStream(fileStream, CompressionLevel.Fastest);
                    break;

                case Mode.Uncompressed:
                    stream = fileStream;
                    break;
                }

                return(new NetworkWriter(stream));
            }
            catch (Exception e)
            {
                Console.Error.WriteLine(e);
            }
            return(null);
        }
예제 #3
0
    unsafe public void InitializeMap(DataGenerator generator)
    {
        // Generate schema the first time we set map info
        bool generateSchema = false;

        if (m_MapInfo.schema == null)
        {
            m_MapInfo.schema = new NetworkSchema(NetworkConfig.mapSchemaId);
            generateSchema   = true;
        }

        // Update map info
        var writer = new NetworkWriter(m_MapInfo.data, 1024, m_MapInfo.schema, generateSchema);

        generator(ref writer);
        writer.Flush();

        m_MapInfo.serverInitSequence = m_ServerSequence;
        ++m_MapInfo.mapId;

        // Reset map and connection state
        serverTime = 0;
        //m_Entities.Clear();
        //m_FreeEntities.Clear();
        foreach (var pair in _serverConnections)
        {
            pair.Value.Reset();
        }
    }
예제 #4
0
        public void QueueCommand(int time, DataGenerator generator)
        {
            var generateSchema = (commandSchema == null);

            if (generateSchema)
            {
                commandSchema = new NetworkSchema(NetworkConfig.networkClientQueueCommandSchemaId);
            }

            var info = commandsOut.Acquire(++commandSequence);

            info.time = time;
            var writer = new NetworkWriter(info.data, commandSchema, generateSchema);

            generator(ref writer);
            writer.Flush();
        }
    public void UpdateGameInfo()
    {
        var writer = new NetworkWriter(m_Msg, null);

        writer.WriteInt32("serverPort", m_ServerPort);
        writer.WriteUInt32("token", gameInfo.token);
        writer.WriteString("servername", gameInfo.servername);
        writer.WriteString("levelname", gameInfo.levelname);
        writer.WriteString("gamemode", gameInfo.gamemode);
        writer.WriteInt32("connectedPlayers", gameInfo.connectedPlayers);
        writer.WriteInt32("maxPlayers", gameInfo.maxPlayers);
        writer.Flush();
        m_MsgSize = writer.GetLength();

        if (m_Broadcasting)
        {
            // TODO : We have to restart the broadcast to update the message but we cannot
            // do this in a single frame since we have to wait for some internal state in UNET
            // to reset, so we try 3 times
            NetworkTransport.StopBroadcastDiscovery();
            m_PendingStartAttempts = 3;
        }
    }
예제 #6
0
        unsafe public static void WriteValues(List <object> values, uint[] buffer, NetworkSchema schema)
        {
            fixed(uint *buf = buffer)
            {
                NetworkWriter writer = new NetworkWriter(buf, buffer.Length, schema);

                for (int j = 0; j < values.Count; ++j)
                {
                    var    value     = values[j];
                    var    field     = schema.fields[j];
                    string fieldName = "field_" + j;
                    if (value is bool)
                    {
                        writer.WriteBoolean(fieldName, (bool)value);
                    }
                    else if (value is byte)
                    {
                        writer.WriteByte(fieldName, (byte)value);
                    }
                    else if (value is ushort)
                    {
                        writer.WriteUInt16(fieldName, (ushort)value);
                    }
                    else if (value is short)
                    {
                        writer.WriteInt16(fieldName, (short)value);
                    }
                    else if (value is uint)
                    {
                        writer.WriteUInt32(fieldName, (uint)value);
                    }
                    else if (value is int)
                    {
                        writer.WriteInt32(fieldName, (int)value);
                    }
                    else if (value is float)
                    {
                        if (field.delta)
                        {
                            writer.WriteFloatQ(fieldName, (float)value, field.precision);
                        }
                        else
                        {
                            writer.WriteFloat(fieldName, (float)value);
                        }
                    }
                    else if (value is Vector2)
                    {
                        if (field.delta)
                        {
                            writer.WriteVector2Q(fieldName, (Vector2)value, field.precision);
                        }
                        else
                        {
                            writer.WriteVector2(fieldName, (Vector2)value);
                        }
                    }
                    else if (value is Vector3)
                    {
                        if (field.delta)
                        {
                            writer.WriteVector3Q(fieldName, (Vector3)value, field.precision);
                        }
                        else
                        {
                            writer.WriteVector3(fieldName, (Vector3)value);
                        }
                    }
                    else if (value is Quaternion)
                    {
                        if (field.delta)
                        {
                            writer.WriteQuaternionQ(fieldName, (Quaternion)value, field.precision);
                        }
                        else
                        {
                            writer.WriteQuaternion(fieldName, (Quaternion)value);
                        }
                    }
                    else if (value is string)
                    {
                        writer.WriteString(fieldName, (string)value, 1024);
                    }
                    else if (value is byte[])
                    {
                        writer.WriteBytes(fieldName, (byte[])value, 0, 10, 1024);
                    }
                    else if (value == null && field.fieldType == NetworkSchema.FieldType.String)
                    {
                        writer.WriteString(fieldName, null, 1024);
                    }
                    else
                    {
                        Assert.Fail();
                    }
                }

                writer.Flush();
            }
        }
예제 #7
0
    unsafe public void GenerateSnapshot(ISnapshotGenerator snapshotGenerator, float simTime)
    {
        var time = snapshotGenerator.WorldTick;

        GameDebug.Assert(time > serverTime);      // Time should always flow forward
        GameDebug.Assert(m_MapInfo.mapId > 0);    // Initialize map before generating snapshot

        ++m_ServerSequence;

        // We currently keep entities around until every client has ack'ed the snapshot with the despawn
        // Then we delete them from our list and recycle the id
        // TODO: we do not need this anymore?

        // Find oldest (smallest seq no) acked snapshot.
        var minClientAck = int.MaxValue;

        foreach (var pair in _serverConnections)
        {
            var c = pair.Value;
            // If a client is so far behind that we have to send non-baseline updates to it
            // there is no reason to keep despawned entities around for this clients sake
            if (m_ServerSequence - c.maxSnapshotAck >= NetworkConfig.snapshotDeltaCacheSize - 2) // -2 because we want 3 baselines!
            {
                continue;
            }
            var acked = c.maxSnapshotAck;
            if (acked < minClientAck)
            {
                minClientAck = acked;
            }
        }

        // Recycle despawned entities that have been acked by all
        for (int i = 0; i < m_Entities.Count; i++)
        {
            var e = m_Entities[i];
            if (e.despawnSequence > 0 && e.despawnSequence < minClientAck)
            {
                //if (serverDebugEntityIds.IntValue > 1)
                //    GameDebug.Log("Recycling entity id: " + i + " because despawned in " + e.despawnSequence + " and minAck is now " + minClientAck);
                e.Reset();
                m_FreeEntities.Add(i);
            }
        }

        serverTime      = time;
        m_ServerSimTime = simTime;

        m_LastEntityCount = 0;

        // Grab world snapshot from circular buffer
        var worldsnapshot = m_Snapshots[m_ServerSequence % m_Snapshots.Length];

        worldsnapshot.serverTime = time;
        worldsnapshot.length     = 0;

        // Run through all the registered network entities and serialize the snapshot
        for (var id = 0; id < m_Entities.Count; id++)
        {
            var entity = m_Entities[id];

            // Skip freed
            if (entity.spawnSequence == 0)
            {
                continue;
            }

            // Skip entities that are depawned
            if (entity.despawnSequence > 0)
            {
                continue;
            }

            // If we are here and are despawned, we must be a despawn/spawn in same frame situation
            GameDebug.Assert(entity.despawnSequence == 0 || entity.despawnSequence == entity.spawnSequence, "Snapshotting entity that was deleted in the past?");
            GameDebug.Assert(entity.despawnSequence == 0 || entity.despawnSequence == m_ServerSequence, "WUT");

            // For now we generate the entity type info the first time we generate a snapshot
            // for the particular entity as a more lightweight approach rather than introducing
            // a full schema system where the game code must generate and register the type
            EntityTypeInfo typeInfo;
            bool           generateSchema = false;
            if (!m_EntityTypes.TryGetValue(entity.typeId, out typeInfo))
            {
                typeInfo = new EntityTypeInfo()
                {
                    name = snapshotGenerator.GenerateEntityName(id), typeId = entity.typeId, createdSequence = m_ServerSequence, schema = new NetworkSchema(entity.typeId + NetworkConfig.firstEntitySchemaId)
                };
                m_EntityTypes.Add(entity.typeId, typeInfo);
                generateSchema = true;
            }

            // Generate entity snapshot
            var snapshotInfo = entity.snapshots.Acquire(m_ServerSequence);
            snapshotInfo.start = worldsnapshot.data + worldsnapshot.length;

            var writer = new NetworkWriter(snapshotInfo.start, NetworkConfig.maxWorldSnapshotDataSize / 4 - worldsnapshot.length, typeInfo.schema, generateSchema);
            snapshotGenerator.GenerateEntitySnapshot(id, ref writer);
            writer.Flush();
            snapshotInfo.length = writer.GetLength();

            worldsnapshot.length += snapshotInfo.length;

            if (entity.despawnSequence == 0)
            {
                m_LastEntityCount++;
            }

            GameDebug.Assert(snapshotInfo.length > 0, "Tried to generate a entity snapshot but no data was delivered by generator?");

            if (generateSchema)
            {
                GameDebug.Assert(typeInfo.baseline == null, "Generating schema twice?");
                // First time a type/schema is encountered, we clone the serialized data and
                // use it as the type-baseline
                typeInfo.baseline = (uint *)UnsafeUtility.Malloc(snapshotInfo.length * 4, UnsafeUtility.AlignOf <UInt32>(), Unity.Collections.Allocator.Persistent);// new uint[snapshot.length];// (uint[])snapshot.data.Clone();
                for (int i = 0; i < snapshotInfo.length; i++)
                {
                    typeInfo.baseline[i] = *(snapshotInfo.start + i);
                }
            }

            // Check if it is different from the previous generated snapshot
            var dirty = !entity.snapshots.Exists(m_ServerSequence - 1);
            if (!dirty)
            {
                var previousSnapshot = entity.snapshots[m_ServerSequence - 1];
                if (previousSnapshot.length != snapshotInfo.length || // TODO how could length differ???
                    UnsafeUtility.MemCmp(previousSnapshot.start, snapshotInfo.start, snapshotInfo.length) != 0)
                {
                    dirty = true;
                }
            }

            if (dirty)
            {
                entity.updateSequence = m_ServerSequence;
            }

            //statsGeneratedEntitySnapshots++;
            //statsSnapshotData += snapshotInfo.length;
        }
        //statsGeneratedSnapshotSize += worldsnapshot.length * 4;
    }