예제 #1
0
        /// <summary>
        /// Message handler for <see cref="DataMessage"/>
        /// </summary>
        /// <param name="msg">The incoming message.</param>
        /// <param name="packet">The buffer containing the message.</param>
        /// <param name="reader">The reader from which the message came.</param>
        /// <returns><see cref="ErrorCode.UnsupportedFeature"/></returns>
        /// <remarks>
        /// At this level, the function is only supported for handling <see cref="Tes.Shapes.MultiShape"/> data packets.
        /// Otherwise it returns an error code.
        /// </remarks>
        protected virtual Error HandleMessage(DataMessage msg, PacketBuffer packet, BinaryReader reader)
        {
            // Retrieve the target shape.
            ShapeCache cache      = (msg.ObjectID == 0) ? _transientCache : _shapeCache;
            int        shapeIndex = (msg.ObjectID == 0) ? _lastTransientIndex : cache.GetShapeIndex(msg.ObjectID);

            if (shapeIndex < 0)
            {
                return(new Error(ErrorCode.InvalidObjectID, msg.ObjectID));
            }

            // Check this is is a multi-shape.
            CreateMessage shape = cache.GetShapeByIndex(shapeIndex);

            if ((shape.Flags & (ushort)ObjectFlag.MultiShape) == 0)
            {
                return(new Error(ErrorCode.UnsupportedFeature));
            }

            // Add to the multi-shape chain.
            int multiShapeHead = cache.GetMultiShapeChainByIndex(shapeIndex);

            // Read new multi-shape block.
            uint  blockItemCount = (uint)reader.ReadUInt16();
            int   initialHead    = multiShapeHead;
            Error error          = ReadMultiShapeBlock(cache, shapeIndex, shape, packet, reader, blockItemCount, ref multiShapeHead);

            // Set the new multi shape chain head (even on failure for better clean up).
            if (multiShapeHead != -1)
            {
                cache.SetMultiShapeChainByIndex(shapeIndex, multiShapeHead);
            }

            if (error.Failed)
            {
                return(error);
            }

            return(new Error());
        }
예제 #2
0
        /// <summary>
        /// Serialises a list of objects to <paramref name="writer"/>
        /// </summary>
        /// <param name="writer">The writer to serialise to.</param>
        /// <param name="objects">The object to write.</param>
        /// <param name="processedCount">Number of objects processed.</param>
        /// <returns>An error code on failure.</returns>
        /// <remarks>
        /// Default serialisation uses the following logic on each object:
        /// <list type="bullet">
        /// <item>Call <see cref="CreateSerialisationShape(ShapeCache, int, CreateMessage)"/> to
        ///       create a temporary shape to match the unity object</item>
        /// <item>Call <see cref="Shapes.Shape.WriteCreate(PacketBuffer)"/> to generate the creation message
        ///       and serialise the packet.</item>
        /// <item>For complex shapes, call <see cref="Shapes.Shape.WriteData(PacketBuffer, ref uint)"/> as required
        ///       and serialise the packets.</item>
        /// </list>
        ///
        /// Using the <see cref="Shapes.Shape"/> classes ensures serialisation is consistent with the server code
        /// and reduces the code maintenance to one code path.
        /// </remarks>
        protected virtual Error SerialiseShapes(BinaryWriter writer, ShapeCache cache, ref uint processedCount)
        {
            // Serialise transient objects.
            PacketBuffer packet = new PacketBuffer();
            Error        err;

            Shapes.Shape        tempShape      = null;
            List <Shapes.Shape> multiShapeList = new List <Shapes.Shape>();
            uint dataMarker = 0;
            int  dataResult = 0;

            Debug.Assert(tempShape != null && tempShape.RoutingID == RoutingID);

            processedCount = 0;
            foreach (int shapeIndex in cache.ShapeIndices)
            {
                tempShape = null;
                ++processedCount;
                CreateMessage shapeData = cache.GetShapeByIndex(shapeIndex);
                if ((shapeData.Flags & (ushort)ObjectFlag.MultiShape) != 0)
                {
                    // Multi-shape. Follow the link.
                    multiShapeList.Clear();
                    int nextIndex = cache.GetMultiShapeChainByIndex(shapeIndex);
                    while (nextIndex != -1)
                    {
                        CreateMessage multiShapeData = cache.GetShapeByIndex(nextIndex);
                        tempShape    = CreateSerialisationShape(cache, shapeIndex, multiShapeData);
                        tempShape.ID = shapeData.ObjectID;
                        if (tempShape != null)
                        {
                            // Successfully created the child. Add to the list.
                            multiShapeList.Add(tempShape);
                        }
                        else
                        {
                            Debug.LogError($"{Name} failed to create multi-shape entry");
                        }
                        nextIndex = cache.GetMultiShapeChainByIndex(nextIndex);
                    }

                    // Create the multi-shape
                    tempShape          = new Shapes.MultiShape(multiShapeList.ToArray());
                    tempShape.ID       = shapeData.ObjectID;
                    tempShape.Category = shapeData.Category;
                    tempShape.SetAttributes(shapeData.Attributes);
                }
                else if (shapeData.ObjectID != ShapeCache.MultiShapeID)
                {
                    tempShape = CreateSerialisationShape(cache, shapeIndex, shapeData);
                }

                if (tempShape != null)
                {
                    tempShape.WriteCreate(packet);
                    packet.FinalisePacket();
                    packet.ExportTo(writer);

                    if (tempShape.IsComplex)
                    {
                        dataResult = 1;
                        dataMarker = 0;
                        while (dataResult > 0)
                        {
                            dataResult = tempShape.WriteData(packet, ref dataMarker);
                            packet.FinalisePacket();
                            packet.ExportTo(writer);
                        }

                        if (dataResult < 0)
                        {
                            return(new Error(ErrorCode.SerialisationFailure));
                        }

                        // Post serialisation extensions.
                        err = PostSerialiseCreateObject(packet, writer, cache, shapeIndex);
                        if (err.Failed)
                        {
                            return(err);
                        }
                    }
                }
                else if (shapeData.ObjectID != ShapeCache.MultiShapeID)
                {
                    return(new Error(ErrorCode.SerialisationFailure));
                }
            }

            return(new Error());
        }