Example #1
0
    public void ReloadModel()
    {
        TypesByName.Clear();
        TypesByType.Clear();

        var context = Getter();

        var types = context.Model.GetEntityTypes();

        foreach (var t in types)
        {
            var ti = new EntityTypeInfo()
            {
                Name       = t.ClrType.Name,
                PrimaryKey = t.FindPrimaryKey().Properties.FirstOrDefault()?.PropertyInfo,
                Type       = t,
                //Getter = getter
            };

            TypesByName.Add(t.ClrType.Name, ti);
            TypesByType.Add(t.ClrType, ti);

            if (!DB.ContainsKey(t.ClrType))
            {
                DB.Add(t.ClrType, new Dictionary <object, WeakReference>());
            }
        }
    }
 public ViewResultBase Details()
 {
     if (!string.IsNullOrEmpty(Request["isTooltip"]))
     {
         Guid id;
         if (Guid.TryParse(Request["id"], out id))
         {
             var data = new EntityTypeInfo(base.EntityType.GetData(id));
             return(new PartialViewResult {
                 ViewName = "Partials/Details", ViewData = new ViewDataDictionary(data)
             });
         }
         else
         {
             throw new ValidationException("非法的Guid标识" + Request["id"]);
         }
     }
     else if (!string.IsNullOrEmpty(Request["isInner"]))
     {
         return(new PartialViewResult {
             ViewName = "Partials/Details"
         });
     }
     else
     {
         return(this.View());
     }
 }
        public void Test()
        {
            TestClass1     o  = new TestClass1();
            EntityTypeInfo et = o.GetEntityInfo();

            Assert.IsNotNull(et);
            Assert.AreEqual(101, et.ID);
            Assert.AreEqual(EntityState.Detached, et.EntityState);
        }
Example #4
0
        internal void A(string entityTypeName, EntityType newEntityType)
        {
            Trace.Assert(this.FindEntityTypeInfo(entityTypeName) == null);
            EntityTypeInfo typeInfo = new EntityTypeInfo();

            typeInfo.entityTypeName = entityTypeName;
            typeInfo.newEntityType  = newEntityType;
            this.aAf.Add(typeInfo);
        }
Example #5
0
        private EntityTypeInfo GetOrCreateEntityTypeInfo(ResourceType entityType)
        {
            if (_types.TryGetValue(entityType, out var info))
            {
                return(info);
            }

            return(_types[entityType] = new EntityTypeInfo());
        }
        public static EntityTypeInfo GetEntityType(int id)
        {
            EntityTypeInfo ret = null;

            using (EntityMetadataContext ctx = EntityMetadataContext.CreateInstance())
            {
                ret = ctx.GetEntityType(id);
            }

            return(ret);
        }
Example #7
0
        public void Reset()
        {
            type = null;
            lastUpdateSequence = 0;
            despawnSequence    = 0;
            fieldMask          = 0;
            // TODO needed?
            for (var i = 0; i < lastUpdate.Length; i++)
            {
                lastUpdate[i] = 0;
            }

            baselines.Clear();
        }
        public EntityTypeInfo GetEntityTypeInfo(Type type, bool addToEntityTypes = false)
        {
            lock (this)
            {
                EntityTypeInfo info;
                if (!entityTypeInfos.TryGetValue(type ?? throw new ArgumentNullException(nameof(type)), out info))
                {
                    info = new EntityTypeInfo(type, this);
                    entityTypeInfos[type] = info;

                    if (addToEntityTypes)
                    {
                        AddEntityType(type);
                    }
                }

                return(info);
            }
        }
Example #9
0
        /// <summary>
        /// Gets the entity type information from the merge field identifier.
        /// </summary>
        /// <param name="mergeFieldId">The merge field identifier.</param>
        /// <returns></returns>
        public static EntityTypeInfo GetEntityTypeInfoFromMergeFieldId(string mergeFieldId)
        {
            var entityTypeInfo  = new EntityTypeInfo();
            var entityTypeParts = mergeFieldId.Split(new char[] { '~' }, StringSplitOptions.RemoveEmptyEntries);
            var entityTypeName  = entityTypeParts[0];
            var entityType      = EntityTypeCache.Get(entityTypeName, false);

            if (entityType?.IsEntity == true)
            {
                entityTypeInfo.EntityType = entityType;
            }
            else
            {
                return(null);
            }

            if (entityTypeParts.Length > 1)
            {
                var entityTypeQualifiersParts = entityTypeParts.Skip(1).ToArray();
                var qualifiers = new List <EntityTypeInfo.EntityTypeQualifier>();

                foreach (var entityTypeQualifiersPart in entityTypeQualifiersParts)
                {
                    var qualifierParts = entityTypeQualifiersPart.Split(new char[] { '+', ' ' }).ToArray();

                    if (qualifierParts.Length == 2)
                    {
                        qualifiers.Add(new EntityTypeInfo.EntityTypeQualifier(qualifierParts[0], qualifierParts[1]));
                    }
                }

                entityTypeInfo.EntityTypeQualifiers = qualifiers.ToArray();
            }

            return(entityTypeInfo);
        }
Example #10
0
        private void AddEntity <TEntity>(TEntity entity, EntityState state)
        {
            if (entity == null)
            {
                return;
            }

            if (!_typeEntities.TryGetValue(typeof(TEntity), out var entityTypeInfo))
            {
                entityTypeInfo = new EntityTypeInfo(_entityMetadataProvider.GetMetadata(typeof(TEntity)));
                _typeEntities.Add(typeof(TEntity), entityTypeInfo);
            }

            var persister = entityTypeInfo.EntityMetadata.EntityPersister;

            if (state == EntityState.Modified && persister.IsVersioned)
            {
                // Simulate breeze js behavior by increasing the version number
                var version = persister.GetPropertyValue(entity, persister.VersionProperty);
                persister.SetPropertyValue(entity, persister.VersionProperty, persister.VersionType.Next(version, null));
            }

            entityTypeInfo.AddEntity(entity, state);
        }
 public ViewResultBase Details()
 {
     if (!string.IsNullOrEmpty(Request["isTooltip"]))
     {
         Guid id;
         if (Guid.TryParse(Request["id"], out id))
         {
             var data = new EntityTypeInfo(base.EntityType.GetData(id));
             return new PartialViewResult { ViewName = "Partials/Details", ViewData = new ViewDataDictionary(data) };
         }
         else
         {
             throw new ValidationException("非法的Guid标识" + Request["id"]);
         }
     }
     else if (!string.IsNullOrEmpty(Request["isInner"]))
     {
         return new PartialViewResult { ViewName = "Partials/Details" };
     }
     else
     {
         return this.View();
     }
 }
Example #12
0
        void ReadSnapshot <TInputStream>(int sequence, ref TInputStream input) where TInputStream : NetworkCompression.IInputStream
        {
            //input.SetStatsType(NetworkCompressionReader.Type.SnapshotSchema);
            counters.snapshotsIn++;

            // Snapshot may be delta compressed against one or more baselines
            // Baselines are indicated by sequence number of the package it was in
            var baseSequence = (int)input.ReadPackedIntDelta(sequence - 1, NetworkConfig.baseSequenceContext);

            bool enableNetworkPrediction = input.ReadRawBits(1) != 0;
            bool enableHashing           = input.ReadRawBits(1) != 0;

            int baseSequence1 = 0;
            int baseSequence2 = 0;

            if (enableNetworkPrediction)
            {
                baseSequence1 = (int)input.ReadPackedIntDelta(baseSequence - 1, NetworkConfig.baseSequence1Context);
                baseSequence2 = (int)input.ReadPackedIntDelta(baseSequence1 - 1, NetworkConfig.baseSequence2Context);
            }

            if (clientDebug.IntValue > 2)
            {
                if (enableNetworkPrediction)
                {
                    GameDebug.Log((baseSequence > 0 ? "Snap [BL]" : "Snap [  ]") + "(" + sequence + ")  " + baseSequence + " - " + baseSequence1 + " - " + baseSequence2);
                }
                else
                {
                    GameDebug.Log((baseSequence > 0 ? "Snap [BL]" : "Snap [  ]") + "(" + sequence + ")  " + baseSequence);
                }
            }

            if (baseSequence == 0)
            {
                counters.fullSnapshotsIn++;
            }

            GameDebug.Assert(baseSequence == 0 ||
                             (sequence > baseSequence && sequence - baseSequence < NetworkConfig.snapshotDeltaCacheSize), "Attempting snapshot encoding with invalid baseline: {0}:{1}", sequence, baseSequence);

            var snapshotInfo = snapshots.Acquire(sequence);

            snapshotInfo.serverTime = (int)input.ReadPackedIntDelta(baseSequence != 0 ? snapshots[baseSequence].serverTime : 0, NetworkConfig.serverTimeContext);

            var temp = (int)input.ReadRawBits(8);

            serverSimTime = temp * 0.1f;

            // Only update time if received in-order..
            // TODO consider dropping out of order snapshots
            // TODO detecting out-of-order on pack sequences
            if (snapshotInfo.serverTime > serverTime)
            {
                serverTime           = snapshotInfo.serverTime;
                snapshotReceivedTime = NetworkUtils.stopwatch.ElapsedMilliseconds;
            }
            else
            {
                GameDebug.Log(string.Format("NetworkClient. Dropping out of order snaphot. Server time:{0} snapshot time:{1}", serverTime, snapshotInfo.serverTime));
            }

            // Read schemas
            var schemaCount = input.ReadPackedUInt(NetworkConfig.schemaCountContext);

            for (int schemaIndex = 0; schemaIndex < schemaCount; ++schemaIndex)
            {
                var typeId = (ushort)input.ReadPackedUInt(NetworkConfig.schemaTypeIdContext);

                var entityType = new EntityTypeInfo()
                {
                    typeId = typeId
                };
                entityType.schema   = NetworkSchema.ReadSchema(ref input);
                entityType.baseline = new byte[NetworkConfig.maxEntitySnapshotDataSize];
                NetworkSchema.CopyFieldsToBuffer(entityType.schema, ref input, entityType.baseline);

                if (!entityTypes.ContainsKey(typeId))
                {
                    entityTypes.Add(typeId, entityType);
                }
            }

            // Remove any despawning entities that belong to older base sequences
            for (int i = 0; i < entities.Count; i++)
            {
                var e = entities[i];
                if (e.type == null)
                {
                    continue;
                }
                if (e.despawnSequence > 0 && e.despawnSequence <= baseSequence)
                {
                    e.Reset();
                }
            }

            // Read new spawns
            m_TempSpawnList.Clear();
            var previousId = 1;
            var spawnCount = input.ReadPackedUInt(NetworkConfig.spawnCountContext);

            for (var spawnIndex = 0; spawnIndex < spawnCount; ++spawnIndex)
            {
                var id = (int)input.ReadPackedIntDelta(previousId, NetworkConfig.idContext);
                previousId = id;

                // Register the entity
                var typeId = (ushort)input.ReadPackedUInt(NetworkConfig.spawnTypeIdContext);    //TODO: use another encoding
                GameDebug.Assert(entityTypes.ContainsKey(typeId), "Spawn request with unknown type id {0}", typeId);

                byte fieldMask = (byte)input.ReadRawBits(8);

                // Check if we already registered the entity since we can receive spawn information
                // in several snapshots before the client has ack a package containing the spawn

                // TODO (petera) need an max entity id for safety
                while (id >= entities.Count)
                {
                    entities.Add(new EntityInfo());
                }

                if (entities[id].type == null)
                {
                    var e = entities[id];
                    e.type      = entityTypes[typeId];
                    e.fieldMask = fieldMask;
                    spawns.Add(id);
                }

                m_TempSpawnList.Add(id);
            }

            // Read despawns
            var despawnCount = input.ReadPackedUInt(NetworkConfig.despawnCountContext);

            for (var despawnIndex = 0; despawnIndex < despawnCount; ++despawnIndex)
            {
                var id = (int)input.ReadPackedIntDelta(previousId, NetworkConfig.idContext);
                previousId = id;

                // we may see despawns many times, only handle if we still have the entity
                GameDebug.Assert(id < entities.Count, "Getting despawn for id {0} but we only know about entities up to {1}", id, entities.Count);
                if (entities[id].type == null)
                {
                    continue;
                }

                var entity = entities[id];

                // Already in the process of being despawned. This happens with same-snapshot spawn/despawn cases
                if (entity.despawnSequence > 0)
                {
                    continue;
                }

                // If we are spawning and despawning in same snapshot, delay actual deletion of
                // entity as we need it around to be able to read the update part of the snapshot
                if (m_TempSpawnList.Contains(id))
                {
                    entity.despawnSequence = sequence; // keep until baseSequence >= despawnSequence
                }
                else
                {
                    entity.Reset(); // otherwise remove right away; no further updates coming, not even in this snap
                }
                // Add to despawns list so we can request despawn from game later
                GameDebug.Assert(!despawns.Contains(id), "Double despawn in same snaphot? {0}", id);
                despawns.Add(id);
            }

            // Predict all active entities
            for (var id = 0; id < entities.Count; id++)
            {
                var info = entities[id];
                if (info.type == null)
                {
                    continue;
                }

                // NOTE : As long as the server haven't gotten the spawn acked, it will keep sending
                // delta relative to 0, so we need to check if the entity was in the spawn list to determine
                // if the delta is relative to the last update or not

                int baseline0Time = 0;

                byte[] baseline0 = info.type.baseline;
                GameDebug.Assert(baseline0 != null, "Unable to find schema baseline for type {0}", info.type.typeId);

                if (baseSequence != 0 && !m_TempSpawnList.Contains(id))
                {
                    baseline0 = info.baselines.FindMax(baseSequence);
                    GameDebug.Assert(baseline0 != null, "Unable to find baseline for seq {0} for id {1}", baseSequence, id);
                    baseline0Time = snapshots[baseSequence].serverTime;
                }

                if (enableNetworkPrediction)
                {
                    uint num_baselines = 1; // 1 because either we have schema baseline or we have a real baseline
                    int  baseline1Time = 0;
                    int  baseline2Time = 0;

                    byte[] baseline1 = null;
                    byte[] baseline2 = null;
                    if (baseSequence1 != baseSequence)
                    {
                        baseline1 = info.baselines.FindMax(baseSequence1);
                        if (baseline1 != null)
                        {
                            num_baselines = 2;
                            baseline1Time = snapshots[baseSequence1].serverTime;
                        }
                        if (baseSequence2 != baseSequence1)
                        {
                            baseline2 = info.baselines.FindMax(baseSequence2);
                            if (baseline2 != null)
                            {
                                num_baselines = 3;
                                baseline2Time = snapshots[baseSequence2].serverTime;
                            }
                        }
                    }

                    // TODO (petera) are these clears needed?
                    for (int i = 0, c = info.fieldsChangedPrediction.Length; i < c; ++i)
                    {
                        info.fieldsChangedPrediction[i] = 0;
                    }
                    for (int i = 0; i < NetworkConfig.maxEntitySnapshotDataSize; i++)
                    {
                        info.prediction[i] = 0;
                    }

                    NetworkPrediction.PredictSnapshot(info.prediction, info.fieldsChangedPrediction, info.type.schema, num_baselines, (uint)baseline0Time, baseline0, (uint)baseline1Time, baseline1, (uint)baseline2Time, baseline2, (uint)snapshotInfo.serverTime, info.fieldMask);
                }
                else
                {
                    var f = info.fieldsChangedPrediction;
                    for (var i = 0; i < f.Length; ++i)
                    {
                        f[i] = 0;
                    }
                    NetworkUtils.MemCopy(baseline0, 0, info.prediction, 0, info.type.schema.GetByteSize());
                }
            }

            // Read updates
            var updateCount = input.ReadPackedUInt(NetworkConfig.updateCountContext);

            for (var updateIndex = 0; updateIndex < updateCount; ++updateIndex)
            {
                var id = (int)input.ReadPackedIntDelta(previousId, NetworkConfig.idContext);
                previousId = id;

                var info = entities[id];

                uint hash = 0;
                // Copy prediction to temp buffer as we now overwrite info.prediction with fully unpacked
                // state by applying incoming delta to prediction.
                NetworkUtils.MemCopy(info.prediction, 0, tempSnapshotBuffer, 0, info.type.schema.GetByteSize());

                DeltaReader.Read(ref input, info.type.schema, info.prediction, tempSnapshotBuffer, info.fieldsChangedPrediction, info.fieldMask, ref hash);
                if (enableHashing)
                {
                    uint hashCheck = input.ReadRawBits(32);

                    if (hash != hashCheck)
                    {
                        GameDebug.Log("Hash check fail for entity " + id);
                        if (enableNetworkPrediction)
                        {
                            GameDebug.Assert(false, "Snapshot (" + snapshotInfo.serverTime + ") " + (baseSequence > 0 ? "Snap [BL]" : "Snap [  ]") + "  " + baseSequence + " - " + baseSequence1 + " - " + baseSequence2 + ". Sche: " + schemaCount + " Spwns: " + spawnCount + " Desp: " + despawnCount + " Upd: " + updateCount);
                        }
                        else
                        {
                            GameDebug.Assert(false, "Snapshot (" + snapshotInfo.serverTime + ") " + (baseSequence > 0 ? "Snap [BL]" : "Snap [  ]") + "  " + baseSequence + ". Sche: " + schemaCount + " Spwns: " + spawnCount + " Desp: " + despawnCount + " Upd: " + updateCount);
                        }
                    }
                }
            }

            uint snapshotHash = 0; // sum of hash for all (updated or not) entity snapshots
            uint numEnts      = 0;

            for (int id = 0; id < entities.Count; id++)
            {
                var info = entities[id];
                if (info.type == null)
                {
                    continue;
                }

                // Skip despawned that have not also been spawned in this snapshot
                if (info.despawnSequence > 0 && !spawns.Contains(id))
                {
                    continue;
                }

                // If just spawned or if new snapshot is different from the last we deserialized,
                // we need to deserialize. Otherwise just ignore; no reason to deserialize the same
                // values again
                int schemaSize = info.type.schema.GetByteSize();
                if (info.baselines.GetSize() == 0 || NetworkUtils.MemCmp(info.prediction, 0, info.lastUpdate, 0, schemaSize) != 0)
                {
                    var data = info.baselines.Insert(sequence);
                    NetworkUtils.MemCopy(info.prediction, 0, data, 0, schemaSize);
                    if (sequence > info.lastUpdateSequence)
                    {
                        if (!updates.Contains(id))
                        {
                            updates.Add(id);
                        }

                        NetworkUtils.MemCopy(info.prediction, 0, info.lastUpdate, 0, schemaSize);
                        info.lastUpdateSequence = sequence;
                    }
                }

                if (enableHashing && info.despawnSequence == 0)
                {
                    snapshotHash += NetworkUtils.SimpleHash(info.prediction, schemaSize);
                    numEnts++;
                }
            }


            if (clientDebug.IntValue > 1)
            {
                if (clientDebug.IntValue > 2 || spawnCount > 0 || despawnCount > 0 || schemaCount > 0 || baseSequence == 0)
                {
                    string entityIds = "";
                    for (var i = 0; i < entities.Count; i++)
                    {
                        entityIds += entities[i].type == null ? ",-" : ("," + i);
                    }
                    string despawnIds = string.Join(",", despawns);
                    string spawnIds   = string.Join(",", spawns);
                    string updateIds  = string.Join(",", updates);

                    if (enableNetworkPrediction)
                    {
                        GameDebug.Log((baseSequence > 0 ? "Snap [BL]" : "Snap [  ]") + "  " + baseSequence + " - " + baseSequence1 + " - " + baseSequence2 + ". Sche: " + schemaCount + " Spwns: " + spawnCount + "(" + spawnIds + ") Desp: " + despawnCount + "(" + despawnIds + ") Upd: " + updateCount + "(" + updateIds + ")  Ents:" + entities.Count + " EntityIds:" + entityIds);
                    }
                    else
                    {
                        GameDebug.Log((baseSequence > 0 ? "Snap [BL]" : "Snap [  ]") + "  " + baseSequence + ". Sche: " + schemaCount + " Spwns: " + spawnCount + "(" + spawnIds + ") Desp: " + despawnCount + "(" + despawnIds + ") Upd: " + updateCount + "(" + updateIds + ")  Ents:" + entities.Count + " EntityIds:" + entityIds);
                    }
                }
            }

            if (enableHashing)
            {
                uint numEntsCheck = input.ReadRawBits(32);
                if (numEntsCheck != numEnts)
                {
                    GameDebug.Log("SYNC PROBLEM: server num ents: " + numEntsCheck + " us:" + numEnts);
                    GameDebug.Assert(false);
                }
            }
        }
 public PropertyElement(string name, string type)
 {
     Name      = name;
     Type      = EntityTypeInfo.GetTypeShortName(type);
     CellStyle = UITableViewCellStyle.Value1;
 }
Example #14
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;
    }
Example #15
0
        internal static bool ResolveEntityProperties(IList <JsonProperty> jsonProperties,
                                                     Type entityType, EntityTypeInfo entityTypeInfo,
                                                     EntityService entityService, DefaultContractResolver resolver,
                                                     Func <PropertyInfo, JsonProperty> createPropertyFunc)
        {
            if (entityService.ContainsEntityType(entityType))
            {
                if (jsonProperties.Any(jp => jp.PropertyName == Defaults.MetadataPropertyName &&
                                       jp.UnderlyingName == Defaults.DummyMetadataPropertyInfo.Name))
                {
                    return(false); //if we ever find the metadata property there, assume it has been resolved.
                }
                var _properties = new JsonPropertyCollection(entityType);

                var isComplex          = entityType.IsComplex();
                var propertiesToIgnore = entityTypeInfo.PropertiesToIgnore.ToArray();

                foreach (var jsonProp in jsonProperties)
                {
                    if (isComplex)
                    {
                        jsonProp.NullValueHandling    = NullValueHandling.Include; //we need null values for complex types
                        jsonProp.DefaultValueHandling =
                            DefaultValueHandling.Include;                          //we need all properties serialized
                    }

                    if (!jsonProp.Ignored &&
                        propertiesToIgnore.Any(np => np.Name == jsonProp.UnderlyingName))
                    {
                        jsonProp.Ignored = true;
                    }

                    _properties.Add(jsonProp);
                }

                lock (entityTypeInfo)
                {
                    //check for complextypes
                    var complexTypedProperties = entityTypeInfo.ComplexTypedProperties;

                    var complexJsonProperties = new List <JsonProperty>();

                    if (complexTypedProperties?.Count > 0)
                    {
                        //filter to complexproperties
                        var filteredJsonProperties = _properties?
                                                     .Select(p => new
                        {
                            JsonProperty = p,
                            PropertyInfo = complexTypedProperties.Where(pi => pi.Name == p.UnderlyingName)
                                           .FirstOrDefault()
                        })
                                                     .Where(np => np.PropertyInfo != null)
                                                     .ToDictionary(np => np.JsonProperty, np => np.PropertyInfo);

                        Func <Type, IList <JsonProperty> > getResolvedPropertiesFunc = t =>
                        {
                            var contract = resolver.ResolveContract(t) as JsonObjectContract;

                            if (contract.Properties?.Count > 0)
                            {
                                ResolveEntityProperties
                                    (contract.Properties, t, entityService.GetEntityTypeInfo(t),
                                    entityService, resolver, createPropertyFunc);
                            }

                            return(contract.Properties);
                        };

                        //generate new properties with new names for the complex types
                        foreach (var complexTypedJsonProp in filteredJsonProperties)
                        {
                            //get the complexTypedProperty's own jsonproperties
                            //include derived classes
                            var derivedTypes = entityService
                                               .GetDerivedEntityTypes(complexTypedJsonProp.Key.PropertyType)?
                                               .Where(t => t.IsComplex()).ToList();

                            if (derivedTypes == null || derivedTypes.Count == 0)
                            {
                                entityService.AddEntityType(complexTypedJsonProp.Key.PropertyType);
                                derivedTypes = new List <Type> {
                                    complexTypedJsonProp.Key.PropertyType
                                };
                            }

                            var childProperties = derivedTypes
                                                  .SelectMany(dt =>
                                                              getResolvedPropertiesFunc(dt)?.Where
                                                                  (p => /*!p.Ignored &&*/ p.PropertyName != Defaults.MetadataPropertyName) ??
                                                              new JsonProperty[0],
                                                              (dt, property) => new
                            {
                                DerivedType = dt,
                                Property    = property
                            })
                                                  .Where(jp => jp.Property != null)
                                                  .GroupBy(jp => jp.Property.PropertyName)
                                                  .Select(jpg => jpg.FirstOrDefault())
                                                  .ToList();

                            foreach (var childProp in childProperties)
                            {
                                //add the child to this type's properties
                                try
                                {
                                    var newChildProp = GetComplexTypedPropertyChild
                                                           (childProp.DerivedType, complexTypedJsonProp.Key,
                                                           complexTypedJsonProp.Value, childProp.Property);

                                    _properties.AddProperty(newChildProp);
                                    complexJsonProperties.Add(newChildProp);
                                }
                                catch (JsonSerializationException e)
                                {
                                    //for some reason member already exists and is duplicate
                                }
                            }

                            //ignore all complex typed properties
                            complexTypedJsonProp.Key.Ignored = true;
                        }
                    }

                    var nextIdx = -1;

                    //clear and re-add these properties
                    jsonProperties.Clear();

                    var orderedProperties = _properties.OrderBy(p => p.Order ?? nextIdx++);

                    foreach (var prop in orderedProperties)
                    {
                        jsonProperties.Add(prop);
                    }

                    //create metadata property and add it last
                    var metadataJsonProperty = createPropertyFunc(Defaults.DummyMetadataPropertyInfo);
                    metadataJsonProperty.PropertyName    = Defaults.MetadataPropertyName;
                    metadataJsonProperty.ValueProvider   = new MetadataValueProvider(entityType, complexJsonProperties);
                    metadataJsonProperty.ShouldSerialize = instance =>
                    {
                        return(!(metadataJsonProperty.ValueProvider as MetadataValueProvider)
                               .BuildMetadata(instance).IsEmpty());
                    };
                    metadataJsonProperty.Order = int.MaxValue; //try to make it the last serialized

                    jsonProperties.Add(metadataJsonProperty);

                    //assign and resolve these properties
                    entityTypeInfo.JsonProperties = new List <JsonProperty>(jsonProperties);

                    return(true);
                }
            }

            return(false);
        }
Example #16
0
        unsafe void ReadSnapshot <TInputStream>(int sequence, ref TInputStream input, ISnapshotConsumer consumer) where TInputStream : NetworkCompression.IInputStream
        {
            //input.SetStatsType(NetworkCompressionReader.Type.SnapshotSchema);
            counters.snapshotsIn++;

            // Snapshot may be delta compressed against one or more baselines
            // Baselines are indicated by sequence number of the package it was in
            var haveBaseline = input.ReadRawBits(1) == 1;
            var baseSequence = (int)input.ReadPackedIntDelta(sequence - 1, NetworkConfig.baseSequenceContext);

            bool enableNetworkPrediction = input.ReadRawBits(1) != 0;
            bool enableHashing           = input.ReadRawBits(1) != 0;

            int baseSequence1 = 0;
            int baseSequence2 = 0;

            if (enableNetworkPrediction)
            {
                baseSequence1 = (int)input.ReadPackedIntDelta(baseSequence - 1, NetworkConfig.baseSequence1Context);
                baseSequence2 = (int)input.ReadPackedIntDelta(baseSequence1 - 1, NetworkConfig.baseSequence2Context);
            }

            if (clientDebug.IntValue > 2)
            {
                if (enableNetworkPrediction)
                {
                    GameDebug.Log((haveBaseline ? "Snap [BL]" : "Snap [  ]") + "(" + sequence + ")  " + baseSequence + " - " + baseSequence1 + " - " + baseSequence2);
                }
                else
                {
                    GameDebug.Log((haveBaseline ? "Snap [BL]" : "Snap [  ]") + "(" + sequence + ")  " + baseSequence);
                }
            }

            if (!haveBaseline)
            {
                counters.fullSnapshotsIn++;
            }

            GameDebug.Assert(!haveBaseline ||
                             (sequence > baseSequence && sequence - baseSequence < NetworkConfig.snapshotDeltaCacheSize), "Attempting snapshot encoding with invalid baseline: {0}:{1}", sequence, baseSequence);

            var snapshotInfo = snapshots.Acquire(sequence);

            snapshotInfo.serverTime = (int)input.ReadPackedIntDelta(haveBaseline ? snapshots[baseSequence].serverTime : 0, NetworkConfig.serverTimeContext);

            var temp = (int)input.ReadRawBits(8);

            serverSimTime = temp * 0.1f;

            // Only update time if received in-order..
            // TODO consider dropping out of order snapshots
            // TODO detecting out-of-order on pack sequences
            if (snapshotInfo.serverTime > serverTime)
            {
                serverTime           = snapshotInfo.serverTime;
                snapshotReceivedTime = NetworkUtils.stopwatch.ElapsedMilliseconds;
            }
            else
            {
                GameDebug.Log(string.Format("NetworkClient. Dropping out of order snaphot. Server time:{0} snapshot time:{1}", serverTime, snapshotInfo.serverTime));
            }

            counters.AddSectionStats("snapShotHeader", input.GetBitPosition2(), new Color(0.5f, 0.5f, 0.5f));

            // Used by thinclient that wants to very cheaply just do minimal handling of
            // snapshots
            if (m_DropSnapshots)
            {
                return;
            }

            // Read schemas
            var schemaCount = input.ReadPackedUInt(NetworkConfig.schemaCountContext);

            for (int schemaIndex = 0; schemaIndex < schemaCount; ++schemaIndex)
            {
                var typeId = (ushort)input.ReadPackedUInt(NetworkConfig.schemaTypeIdContext);

                var entityType = new EntityTypeInfo()
                {
                    typeId = typeId
                };
                entityType.schema = NetworkSchema.ReadSchema(ref input);
                counters.AddSectionStats("snapShotSchemas", input.GetBitPosition2(), new Color(0.0f, (schemaIndex & 1) == 1 ? 0.5f : 1.0f, 1.0f));
                entityType.baseline = new uint[NetworkConfig.maxEntitySnapshotDataSize];
                NetworkSchema.CopyFieldsToBuffer(entityType.schema, ref input, entityType.baseline);

                if (!entityTypes.ContainsKey(typeId))
                {
                    entityTypes.Add(typeId, entityType);
                }

                counters.AddSectionStats("snapShotSchemas", input.GetBitPosition2(), new Color(1.0f, (schemaIndex & 1) == 1 ? 0.5f : 1.0f, 1.0f));
            }

            // Remove any despawning entities that belong to older base sequences
            for (int i = 0; i < entities.Count; i++)
            {
                var e = entities[i];
                if (e.type == null)
                {
                    continue;
                }
                if (e.despawnSequence > 0 && e.despawnSequence <= baseSequence)
                {
                    e.Reset();
                }
            }

            // Read new spawns
            m_TempSpawnList.Clear();
            var previousId = 1;
            var spawnCount = input.ReadPackedUInt(NetworkConfig.spawnCountContext);

            for (var spawnIndex = 0; spawnIndex < spawnCount; ++spawnIndex)
            {
                var id = (int)input.ReadPackedIntDelta(previousId, NetworkConfig.idContext);
                previousId = id;

                // Register the entity
                var typeId = (ushort)input.ReadPackedUInt(NetworkConfig.spawnTypeIdContext);    //TODO: use another encoding
                GameDebug.Assert(entityTypes.ContainsKey(typeId), "Spawn request with unknown type id {0}", typeId);

                byte fieldMask = (byte)input.ReadRawBits(8);

                // TODO (petera) need an max entity id for safety
                while (id >= entities.Count)
                {
                    entities.Add(new EntityInfo());
                }

                // Incoming spawn of different type than what we have for this id, so immediately nuke
                // the one we have to make room for the incoming
                if (entities[id].type != null && entities[id].type.typeId != typeId)
                {
                    // This should only ever happen in case of no baseline as normally the server will
                    // not reuse an id before all clients have acknowledged its despawn.
                    GameDebug.Assert(haveBaseline == false, "Spawning entity but we already have with different type?");
                    GameDebug.Log("REPLACING old entity: " + id + " because snapshot gave us new type for this id");
                    despawns.Add(id);
                    entities[id].Reset();
                }

                // We can receive spawn information in several snapshots before our ack
                // has reached the server. Only pass on spawn to game layer once
                if (entities[id].type == null)
                {
                    var e = entities[id];
                    e.type      = entityTypes[typeId];
                    e.fieldMask = fieldMask;
                    spawns.Add(id);
                }

                m_TempSpawnList.Add(id);
            }

            counters.AddSectionStats("snapShotSpawns", input.GetBitPosition2(), new Color(0, 0.58f, 0));

            // Read despawns
            var despawnCount = input.ReadPackedUInt(NetworkConfig.despawnCountContext);

            // If we have no baseline, we need to clear all entities that are not being spawned
            if (!haveBaseline)
            {
                GameDebug.Assert(despawnCount == 0, "There should not be any despawns in a non-baseline snapshot");
                for (int i = 0, c = entities.Count; i < c; ++i)
                {
                    var e = entities[i];
                    if (e.type == null)
                    {
                        continue;
                    }
                    if (m_TempSpawnList.Contains(i))
                    {
                        continue;
                    }
                    GameDebug.Log("NO BL SO PRUNING Stale entity: " + i);
                    despawns.Add(i);
                    e.Reset();
                }
            }

            for (var despawnIndex = 0; despawnIndex < despawnCount; ++despawnIndex)
            {
                var id = (int)input.ReadPackedIntDelta(previousId, NetworkConfig.idContext);
                previousId = id;

                // we may see despawns many times, only handle if we still have the entity
                GameDebug.Assert(id < entities.Count, "Getting despawn for id {0} but we only know about entities up to {1}", id, entities.Count);
                if (entities[id].type == null)
                {
                    continue;
                }

                var entity = entities[id];

                // Already in the process of being despawned. This happens with same-snapshot spawn/despawn cases
                if (entity.despawnSequence > 0)
                {
                    continue;
                }

                // If we are spawning and despawning in same snapshot, delay actual deletion of
                // entity as we need it around to be able to read the update part of the snapshot
                if (m_TempSpawnList.Contains(id))
                {
                    entity.despawnSequence = sequence; // keep until baseSequence >= despawnSequence
                }
                else
                {
                    entity.Reset(); // otherwise remove right away; no further updates coming, not even in this snap
                }
                // Add to despawns list so we can request despawn from game later
                GameDebug.Assert(!despawns.Contains(id), "Double despawn in same snaphot? {0}", id);
                despawns.Add(id);
            }

            counters.AddSectionStats("snapShotDespawns", input.GetBitPosition2(), new Color(0.49f, 0, 0));

            // Predict all active entities
            for (var id = 0; id < entities.Count; id++)
            {
                var info = entities[id];
                if (info.type == null)
                {
                    continue;
                }

                // NOTE : As long as the server haven't gotten the spawn acked, it will keep sending
                // delta relative to 0, so we need to check if the entity was in the spawn list to determine
                // if the delta is relative to the last update or not

                int baseline0Time = 0;

                uint[] baseline0 = info.type.baseline;
                GameDebug.Assert(baseline0 != null, "Unable to find schema baseline for type {0}", info.type.typeId);

                if (haveBaseline && !m_TempSpawnList.Contains(id))
                {
                    baseline0 = info.baselines.FindMax(baseSequence);
                    GameDebug.Assert(baseline0 != null, "Unable to find baseline for seq {0} for id {1}", baseSequence, id);
                    baseline0Time = snapshots[baseSequence].serverTime;
                }

                if (enableNetworkPrediction)
                {
                    uint num_baselines = 1; // 1 because either we have schema baseline or we have a real baseline
                    int  baseline1Time = 0;
                    int  baseline2Time = 0;

                    uint[] baseline1 = null;
                    uint[] baseline2 = null;
                    if (baseSequence1 != baseSequence)
                    {
                        baseline1 = info.baselines.FindMax(baseSequence1);
                        if (baseline1 != null)
                        {
                            num_baselines = 2;
                            baseline1Time = snapshots[baseSequence1].serverTime;
                        }
                        if (baseSequence2 != baseSequence1)
                        {
                            baseline2 = info.baselines.FindMax(baseSequence2);
                            if (baseline2 != null)
                            {
                                num_baselines = 3;
                                baseline2Time = snapshots[baseSequence2].serverTime;
                            }
                        }
                    }

                    // TODO (petera) are these clears needed?
                    for (int i = 0, c = info.fieldsChangedPrediction.Length; i < c; ++i)
                    {
                        info.fieldsChangedPrediction[i] = 0;
                    }
                    for (int i = 0; i < NetworkConfig.maxEntitySnapshotDataSize; i++)
                    {
                        info.prediction[i] = 0;

                        fixed(uint *prediction = info.prediction, baseline0p = baseline0, baseline1p = baseline1, baseline2p = baseline2)
                        {
                            NetworkPrediction.PredictSnapshot(prediction, info.fieldsChangedPrediction, info.type.schema, num_baselines, (uint)baseline0Time, baseline0p, (uint)baseline1Time, baseline1p, (uint)baseline2Time, baseline2p, (uint)snapshotInfo.serverTime, info.fieldMask);
                        }
                }
                else
                {
                    var f = info.fieldsChangedPrediction;
                    for (var i = 0; i < f.Length; ++i)
                    {
                        f[i] = 0;
                    }
                    for (int i = 0, c = info.type.schema.GetByteSize() / 4; i < c; ++i)
                    {
                        info.prediction[i] = baseline0[i];
                    }
                }
            }

            // Read updates
            var updateCount = input.ReadPackedUInt(NetworkConfig.updateCountContext);

            for (var updateIndex = 0; updateIndex < updateCount; ++updateIndex)
            {
                var id = (int)input.ReadPackedIntDelta(previousId, NetworkConfig.idContext);
                previousId = id;

                var info = entities[id];

                uint hash = 0;
                // Copy prediction to temp buffer as we now overwrite info.prediction with fully unpacked
                // state by applying incoming delta to prediction.
                for (int i = 0, c = info.type.schema.GetByteSize() / 4; i < c; ++i)
                {
                    tempSnapshotBuffer[i] = info.prediction[i];
                }

                DeltaReader.Read(ref input, info.type.schema, info.prediction, tempSnapshotBuffer, info.fieldsChangedPrediction, info.fieldMask, ref hash);
                if (enableHashing)
                {
                    uint hashCheck = input.ReadRawBits(32);

                    if (hash != hashCheck)
                    {
                        GameDebug.Log("Hash check fail for entity " + id);
                        if (enableNetworkPrediction)
                        {
                            GameDebug.Assert(false, "Snapshot (" + snapshotInfo.serverTime + ") " + (haveBaseline ? "Snap [BL]" : "Snap [  ]") + "  " + baseSequence + " - " + baseSequence1 + " - " + baseSequence2 + ". Sche: " + schemaCount + " Spwns: " + spawnCount + " Desp: " + despawnCount + " Upd: " + updateCount);
                        }
                        else
                        {
                            GameDebug.Assert(false, "Snapshot (" + snapshotInfo.serverTime + ") " + (haveBaseline ? "Snap [BL]" : "Snap [  ]") + "  " + baseSequence + ". Sche: " + schemaCount + " Spwns: " + spawnCount + " Desp: " + despawnCount + " Upd: " + updateCount);
                        }
                    }
                }
            }

            if (enableNetworkPrediction)
            {
                counters.AddSectionStats("snapShotUpdatesPredict", input.GetBitPosition2(), haveBaseline ? new Color(0.09f, 0.38f, 0.93f) : Color.cyan);
            }
            else
            {
                counters.AddSectionStats("snapShotUpdatesNoPredict", input.GetBitPosition2(), haveBaseline ? new Color(0.09f, 0.38f, 0.93f) : Color.cyan);
            }

            uint snapshotHash = 0; // sum of hash for all (updated or not) entity snapshots
            uint numEnts      = 0;

            for (int id = 0; id < entities.Count; id++)
            {
                var info = entities[id];
                if (info.type == null)
                {
                    continue;
                }

                // Skip despawned that have not also been spawned in this snapshot
                if (info.despawnSequence > 0 && !spawns.Contains(id))
                {
                    continue;
                }

                // If just spawned or if new snapshot is different from the last we deserialized,
                // we need to deserialize. Otherwise just ignore; no reason to deserialize the same
                // values again
                int schemaSize = info.type.schema.GetByteSize();
                if (info.baselines.GetSize() == 0 || NetworkUtils.MemCmp(info.prediction, 0, info.lastUpdate, 0, schemaSize) != 0)
                {
                    var data = info.baselines.Insert(sequence);
                    for (int i = 0; i < schemaSize / 4; ++i)
                        data[i] = info.prediction[i]; }
                    if (sequence > info.lastUpdateSequence)
                    {
                        if (!updates.Contains(id))
                        {
                            updates.Add(id);
                        }

                        for (int i = 0; i < schemaSize / 4; ++i)
                        {
                            info.lastUpdate[i] = info.prediction[i];
                        }
                        info.lastUpdateSequence = sequence;
                    }
                }

                if (enableHashing && info.despawnSequence == 0)
                {
                    snapshotHash += NetworkUtils.SimpleHash(info.prediction, schemaSize);
                    numEnts++;
                }
            }
 private void InitializeEntityInfo(EntityTypeInfo entityInfo, JsonSerializer serializer)
 {
     entityInfo.ResolveJsonPropertiesUsing(serializer.ContractResolver as DefaultContractResolver);
 }