/// <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()); }
/// <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()); }