123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868 |
- #if !BESTHTTP_DISABLE_SIGNALR_CORE && BESTHTTP_SIGNALR_CORE_ENABLE_GAMEDEVWARE_MESSAGEPACK
- using System;
- using System.Collections.Generic;
- using BestHTTP.PlatformSupport.Memory;
- using BestHTTP.SignalRCore.Messages;
- using GameDevWare.Serialization;
- using GameDevWare.Serialization.MessagePack;
- using GameDevWare.Serialization.Serializers;
- using UnityEngine;
- namespace BestHTTP.SignalRCore.Encoders
- {
- public sealed class MessagePackProtocolSerializationOptions
- {
- /// <summary>
- /// A function that must return a TypeSerializer for the given Type. To serialize an enum it can return an EnumNumberSerializer (default) to serialize enums as numbers or EnumSerializer to serialize them as strings.
- /// </summary>
- public Func<Type, TypeSerializer> EnumSerializerFactory;
- }
- /// <summary>
- /// IPRotocol implementation using the "Json & MessagePack Serialization" asset store package (https://assetstore.unity.com/packages/tools/network/json-messagepack-serialization-59918).
- /// </summary>
- public sealed class MessagePackProtocol : BestHTTP.SignalRCore.IProtocol
- {
- public string Name { get { return "messagepack"; } }
- public TransferModes Type { get { return TransferModes.Binary; } }
- public IEncoder Encoder { get; private set; }
- public HubConnection Connection { get; set; }
- public MessagePackProtocolSerializationOptions Options { get; set; }
- public MessagePackProtocol()
- : this(new MessagePackProtocolSerializationOptions { EnumSerializerFactory = (enumType) => new EnumNumberSerializer(enumType) })
- {
-
- }
- public MessagePackProtocol(MessagePackProtocolSerializationOptions options)
- {
- this.Options = options;
- GameDevWare.Serialization.Json.DefaultSerializers.Clear();
- GameDevWare.Serialization.Json.DefaultSerializers.AddRange(new TypeSerializer[]
- {
- new BinarySerializer(),
- new DateTimeOffsetSerializer(),
- new DateTimeSerializer(),
- new GuidSerializer(),
- new StreamSerializer(),
- new UriSerializer(),
- new VersionSerializer(),
- new TimeSpanSerializer(),
- new DictionaryEntrySerializer(),
- new BestHTTP.SignalRCore.Encoders.Vector2Serializer(),
- new BestHTTP.SignalRCore.Encoders.Vector3Serializer(),
- new BestHTTP.SignalRCore.Encoders.Vector4Serializer(),
- new PrimitiveSerializer(typeof (bool)),
- new PrimitiveSerializer(typeof (byte)),
- new PrimitiveSerializer(typeof (decimal)),
- new PrimitiveSerializer(typeof (double)),
- new PrimitiveSerializer(typeof (short)),
- new PrimitiveSerializer(typeof (int)),
- new PrimitiveSerializer(typeof (long)),
- new PrimitiveSerializer(typeof (sbyte)),
- new PrimitiveSerializer(typeof (float)),
- new PrimitiveSerializer(typeof (ushort)),
- new PrimitiveSerializer(typeof (uint)),
- new PrimitiveSerializer(typeof (ulong)),
- new PrimitiveSerializer(typeof (string)),
- });
- }
- /// <summary>
- /// This function must convert all element in the arguments array to the corresponding type from the argTypes array.
- /// </summary>
- public object[] GetRealArguments(Type[] argTypes, object[] arguments)
- {
- if (arguments == null || arguments.Length == 0)
- return null;
- if (argTypes.Length > arguments.Length)
- throw new Exception(string.Format("argType.Length({0}) < arguments.length({1})", argTypes.Length, arguments.Length));
- return arguments;
- }
- /// <summary>
- /// Convert a value to the given type.
- /// </summary>
- public object ConvertTo(Type toType, object obj)
- {
- if (obj == null)
- return null;
- #if NETFX_CORE
- TypeInfo typeInfo = toType.GetTypeInfo();
- #endif
- #if NETFX_CORE
- if (typeInfo.IsEnum)
- #else
- if (toType.IsEnum)
- #endif
- return Enum.Parse(toType, obj.ToString(), true);
- #if NETFX_CORE
- if (typeInfo.IsPrimitive)
- #else
- if (toType.IsPrimitive)
- #endif
- return Convert.ChangeType(obj, toType);
- if (toType == typeof(string))
- return obj.ToString();
- #if NETFX_CORE
- if (typeInfo.IsGenericType && toType.Name == "Nullable`1")
- return Convert.ChangeType(obj, toType.GenericTypeArguments[0]);
- #else
- if (toType.IsGenericType && toType.Name == "Nullable`1")
- return Convert.ChangeType(obj, toType.GetGenericArguments()[0]);
- #endif
- return obj;
- }
- /// <summary>
- /// This function must return the encoded representation of the given message.
- /// </summary>
- public BufferSegment EncodeMessage(Message message)
- {
- var memBuffer = BufferPool.Get(256, true);
- var stream = new BestHTTP.Extensions.BufferPoolMemoryStream(memBuffer, 0, memBuffer.Length, true, true, false, true);
- // Write 5 bytes for placeholder for length prefix
- stream.WriteByte(0);
- stream.WriteByte(0);
- stream.WriteByte(0);
- stream.WriteByte(0);
- stream.WriteByte(0);
- var buffer = BufferPool.Get(MsgPackWriter.DEFAULT_BUFFER_SIZE, true);
-
- var context = new SerializationContext {
- Options = SerializationOptions.SuppressTypeInformation,
- EnumSerializerFactory = this.Options.EnumSerializerFactory,
- ExtensionTypeHandler = CustomMessagePackExtensionTypeHandler.Instance
- };
- var writer = new MsgPackWriter(stream, context, buffer);
- switch (message.type)
- {
- case MessageTypes.StreamItem:
- // https://github.com/aspnet/AspNetCore/blob/master/src/SignalR/docs/specs/HubProtocol.md#streamitem-message-encoding-1
- // [2, Headers, InvocationId, Item]
- writer.WriteArrayBegin(4);
- writer.WriteNumber(2);
- WriteHeaders(writer);
- writer.WriteString(message.invocationId);
- WriteValue(writer, message.item);
- writer.WriteArrayEnd();
- break;
- case MessageTypes.Completion:
- // https://github.com/aspnet/AspNetCore/blob/master/src/SignalR/docs/specs/HubProtocol.md#completion-message-encoding-1
- // [3, Headers, InvocationId, ResultKind, Result?]
- byte resultKind = (byte)(!string.IsNullOrEmpty(message.error) ? /*error*/ 1 : message.result != null ? /*non-void*/ 3 : /*void*/ 2);
- writer.WriteArrayBegin(resultKind == 2 ? 4 : 5);
- writer.WriteNumber(3);
- WriteHeaders(writer);
- writer.WriteString(message.invocationId);
- writer.WriteNumber(resultKind);
- if (resultKind == 1) // error
- writer.WriteString(message.error);
- else if (resultKind == 3) // non-void
- WriteValue(writer, message.result);
- writer.WriteArrayEnd();
- break;
- case MessageTypes.Invocation:
- // https://github.com/aspnet/AspNetCore/blob/master/src/SignalR/docs/specs/HubProtocol.md#invocation-message-encoding-1
- // [1, Headers, InvocationId, NonBlocking, Target, [Arguments], [StreamIds]]
- case MessageTypes.StreamInvocation:
- // https://github.com/aspnet/AspNetCore/blob/master/src/SignalR/docs/specs/HubProtocol.md#streaminvocation-message-encoding-1
- // [4, Headers, InvocationId, Target, [Arguments], [StreamIds]]
- writer.WriteArrayBegin(message.streamIds != null ? 6 : 5);
- writer.WriteNumber((int)message.type);
- WriteHeaders(writer);
- writer.WriteString(message.invocationId);
- writer.WriteString(message.target);
- writer.WriteArrayBegin(message.arguments != null ? message.arguments.Length : 0);
- if (message.arguments != null)
- for (int i = 0; i < message.arguments.Length; ++i)
- WriteValue(writer, message.arguments[i]);
- writer.WriteArrayEnd();
- if (message.streamIds != null)
- {
- writer.WriteArrayBegin(message.streamIds.Length);
- for (int i = 0; i < message.streamIds.Length; ++i)
- WriteValue(writer, message.streamIds[i]);
- writer.WriteArrayEnd();
- }
- writer.WriteArrayEnd();
- break;
- case MessageTypes.CancelInvocation:
- // https://github.com/aspnet/AspNetCore/blob/master/src/SignalR/docs/specs/HubProtocol.md#cancelinvocation-message-encoding-1
- // [5, Headers, InvocationId]
- writer.WriteArrayBegin(3);
- writer.WriteNumber(5);
- WriteHeaders(writer);
- writer.WriteString(message.invocationId);
- writer.WriteArrayEnd();
- break;
- case MessageTypes.Ping:
- // https://github.com/aspnet/AspNetCore/blob/master/src/SignalR/docs/specs/HubProtocol.md#ping-message-encoding-1
- // [6]
- writer.WriteArrayBegin(1);
- writer.WriteNumber(6);
- writer.WriteArrayEnd();
- break;
- case MessageTypes.Close:
- // https://github.com/aspnet/AspNetCore/blob/master/src/SignalR/docs/specs/HubProtocol.md#close-message-encoding-1
- // [7, Error, AllowReconnect?]
- writer.WriteArrayBegin(string.IsNullOrEmpty(message.error) ? 1 : 2);
- writer.WriteNumber(7);
- if (!string.IsNullOrEmpty(message.error))
- writer.WriteString(message.error);
- writer.WriteArrayEnd();
- break;
- }
- writer.Flush();
- // release back the buffer we used for the MsgPackWriter
- BufferPool.Release(buffer);
- // get how much bytes got written to the buffer. This includes the 5 placeholder bytes too.
- int length = (int)stream.Position;
- // this is the length without the 5 placeholder bytes
- int contentLength = length - 5;
- // get the stream's internal buffer. We set the releaseBuffer flag to false, so we can use it safely.
- buffer = stream.GetBuffer();
- // add varint length prefix
- byte prefixBytes = GetRequiredBytesForLengthPrefix(contentLength);
- WriteLengthAsVarInt(buffer, 5 - prefixBytes, contentLength);
- // return with the final segment
- return new BufferSegment(buffer, 5 - prefixBytes, contentLength + prefixBytes);
- }
- private void WriteValue(MsgPackWriter writer, object value)
- {
- if (value == null)
- writer.WriteNull();
- else
- writer.WriteValue(value, value.GetType());
- }
- private void WriteHeaders(MsgPackWriter writer)
- {
- writer.WriteObjectBegin(0);
- writer.WriteObjectEnd();
- }
- /// <summary>
- /// This function must parse binary representation of the messages into the list of Messages.
- /// </summary>
- public void ParseMessages(BufferSegment segment, ref List<Message> messages)
- {
- messages.Clear();
- int offset = segment.Offset;
- while (offset < segment.Count)
- {
- int length = (int)ReadVarInt(segment.Data, ref offset);
- using (var stream = new System.IO.MemoryStream(segment.Data, offset, length))
- {
- var buff = BufferPool.Get(MsgPackReader.DEFAULT_BUFFER_SIZE, true);
- try
- {
- var context = new SerializationContext {
- Options = SerializationOptions.SuppressTypeInformation,
- ExtensionTypeHandler = CustomMessagePackExtensionTypeHandler.Instance
- };
- var reader = new MsgPackReader(stream, context, Endianness.BigEndian, buff);
-
- reader.NextToken();
- reader.NextToken();
- int messageType = reader.ReadByte();
- switch ((MessageTypes)messageType)
- {
- case MessageTypes.Invocation: messages.Add(ReadInvocation(reader)); break;
- case MessageTypes.StreamItem: messages.Add(ReadStreamItem(reader)); break;
- case MessageTypes.Completion: messages.Add(ReadCompletion(reader)); break;
- case MessageTypes.StreamInvocation: messages.Add(ReadStreamInvocation(reader)); break;
- case MessageTypes.CancelInvocation: messages.Add(ReadCancelInvocation(reader)); break;
- case MessageTypes.Ping:
- // https://github.com/aspnet/AspNetCore/blob/master/src/SignalR/docs/specs/HubProtocol.md#ping-message-encoding-1
- messages.Add(new Message { type = MessageTypes.Ping });
- break;
- case MessageTypes.Close: messages.Add(ReadClose(reader)); break;
- }
- reader.NextToken();
- }
- finally
- {
- BufferPool.Release(buff);
- }
- }
- offset += length;
- }
- }
- private Message ReadClose(MsgPackReader reader)
- {
- // https://github.com/aspnet/AspNetCore/blob/master/src/SignalR/docs/specs/HubProtocol.md#close-message-encoding-1
- string error = reader.ReadString();
- bool allowReconnect = false;
- try
- {
- allowReconnect = reader.ReadBoolean();
- }
- catch { }
- return new Message
- {
- type = MessageTypes.Close,
- error = error,
- allowReconnect = allowReconnect
- };
- }
- private Message ReadCancelInvocation(MsgPackReader reader)
- {
- // https://github.com/aspnet/AspNetCore/blob/master/src/SignalR/docs/specs/HubProtocol.md#cancelinvocation-message-encoding-1
- ReadHeaders(reader);
- string invocationId = reader.ReadString();
- return new Message
- {
- type = MessageTypes.CancelInvocation,
- invocationId = invocationId
- };
- }
- private Message ReadStreamInvocation(MsgPackReader reader)
- {
- // https://github.com/aspnet/AspNetCore/blob/master/src/SignalR/docs/specs/HubProtocol.md#streaminvocation-message-encoding-1
- ReadHeaders(reader);
- string invocationId = reader.ReadString();
- string target = reader.ReadString();
- object[] arguments = ReadArguments(reader, target);
- string[] streamIds = ReadStreamIds(reader);
- return new Message
- {
- type = MessageTypes.StreamInvocation,
- invocationId = invocationId,
- target = target,
- arguments = arguments,
- streamIds = streamIds
- };
- }
- private Message ReadCompletion(MsgPackReader reader)
- {
- // https://github.com/aspnet/AspNetCore/blob/master/src/SignalR/docs/specs/HubProtocol.md#completion-message-encoding-1
- ReadHeaders(reader);
- string invocationId = reader.ReadString();
- byte resultKind = reader.ReadByte();
- switch(resultKind)
- {
- // 1 - Error result - Result contains a String with the error message
- case 1:
- string error = reader.ReadString();
- return new Message
- {
- type = MessageTypes.Completion,
- invocationId = invocationId,
- error = error
- };
- // 2 - Void result - Result is absent
- case 2:
- return new Message
- {
- type = MessageTypes.Completion,
- invocationId = invocationId
- };
- // 3 - Non-Void result - Result contains the value returned by the server
- case 3:
- object item = ReadItem(reader, invocationId);
- return new Message
- {
- type = MessageTypes.Completion,
- invocationId = invocationId,
- item = item,
- result = item
- };
- default:
- throw new NotImplementedException("Unknown resultKind: " + resultKind);
- }
- }
- private Message ReadStreamItem(MsgPackReader reader)
- {
- // https://github.com/aspnet/AspNetCore/blob/master/src/SignalR/docs/specs/HubProtocol.md#streamitem-message-encoding-1
- ReadHeaders(reader);
- string invocationId = reader.ReadString();
- object item = ReadItem(reader, invocationId);
- return new Message
- {
- type = MessageTypes.StreamItem,
- invocationId = invocationId,
- item = item
- };
- }
- private Message ReadInvocation(MsgPackReader reader)
- {
- // https://github.com/aspnet/AspNetCore/blob/master/src/SignalR/docs/specs/HubProtocol.md#invocation-message-encoding-1
- ReadHeaders(reader);
- string invocationId = reader.ReadString();
- string target = reader.ReadString();
- object[] arguments = ReadArguments(reader, target);
- string[] streamIds = ReadStreamIds(reader);
- return new Message
- {
- type = MessageTypes.Invocation,
- invocationId = invocationId,
- target = target,
- arguments = arguments,
- streamIds = streamIds
- };
- }
- private object ReadItem(MsgPackReader reader, string invocationId)
- {
- long longId = 0;
- if (long.TryParse(invocationId, out longId))
- {
- Type itemType = this.Connection.GetItemType(longId);
- return reader.ReadValue(itemType);
- }
- else
- return reader.ReadValue(typeof(object));
- }
- private string[] ReadStreamIds(MsgPackReader reader)
- {
- return reader.ReadValue(typeof(string[])) as string[];
- }
- private object[] ReadArguments(MsgPackReader reader, string target)
- {
- var subscription = this.Connection.GetSubscription(target);
- object[] args;
- if (subscription == null || subscription.callbacks == null || subscription.callbacks.Count == 0)
- {
- args = reader.ReadValue(typeof(object[])) as object[];
- }
- else
- {
- reader.NextToken();
- if (subscription.callbacks[0].ParamTypes != null)
- {
- args = new object[subscription.callbacks[0].ParamTypes.Length];
- for (int i = 0; i < subscription.callbacks[0].ParamTypes.Length; ++i)
- args[i] = reader.ReadValue(subscription.callbacks[0].ParamTypes[i]);
- }
- else
- args = null;
- reader.NextToken();
- }
- return args;
- }
- private Dictionary<string, string> ReadHeaders(MsgPackReader reader)
- {
- return reader.ReadValue(typeof(Dictionary<string, string>)) as Dictionary<string, string>;
- }
- public static byte GetRequiredBytesForLengthPrefix(int length)
- {
- byte bytes = 0;
- do
- {
- length >>= 7;
- bytes++;
- }
- while (length > 0);
- return bytes;
- }
- public static int WriteLengthAsVarInt(byte[] data, int offset, int length)
- {
- do
- {
- var current = data[offset];
- current = (byte)(length & 0x7f);
- length >>= 7;
- if (length > 0)
- {
- current |= 0x80;
- }
- data[offset++] = current;
- }
- while (length > 0);
- return offset;
- }
- public static uint ReadVarInt(byte[] data, ref int offset)
- {
- var length = 0U;
- var numBytes = 0;
- byte byteRead;
- do
- {
- byteRead = data[offset + numBytes];
- length = length | (((uint)(byteRead & 0x7f)) << (numBytes * 7));
- numBytes++;
- }
- while (offset + numBytes < data.Length && ((byteRead & 0x80) != 0));
- offset += numBytes;
- return length;
- }
- }
- public sealed class CustomMessagePackExtensionTypeHandler : MessagePackExtensionTypeHandler
- {
- public const int EXTENSION_TYPE_DATE_TIME = -1;
- public const int DATE_TIME_SIZE = 8;
- public const long BclSecondsAtUnixEpoch = 62135596800;
- public const int NanosecondsPerTick = 100;
- public static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
- private static readonly Type[] DefaultExtensionTypes = new[] { typeof(DateTime) };
- public static CustomMessagePackExtensionTypeHandler Instance = new CustomMessagePackExtensionTypeHandler();
- public override IEnumerable<Type> ExtensionTypes
- {
- get { return DefaultExtensionTypes; }
- }
-
- public override bool TryRead(sbyte type, ArraySegment<byte> data, out object value)
- {
- if (data.Array == null) throw new ArgumentNullException("data");
- value = default(object);
- switch (type)
- {
- case EXTENSION_TYPE_DATE_TIME:
- switch (data.Count)
- {
- case 4:
- {
- var intValue = unchecked((int)(FromBytes(data.Array, data.Offset, 4)));
- value = CustomMessagePackExtensionTypeHandler.UnixEpoch.AddSeconds(unchecked((uint)intValue));
- return true;
- }
- case 8:
- {
- long longValue = FromBytes(data.Array, data.Offset, 8);
- ulong ulongValue = unchecked((ulong)longValue);
- long nanoseconds = (long)(ulongValue >> 34);
- ulong seconds = ulongValue & 0x00000003ffffffffL;
- value = CustomMessagePackExtensionTypeHandler.UnixEpoch.AddSeconds(seconds).AddTicks(nanoseconds / CustomMessagePackExtensionTypeHandler.NanosecondsPerTick);
- return true;
- }
- case 12:
- {
- var intValue = unchecked((int)(FromBytes(data.Array, data.Offset, 4)));
- long longValue = FromBytes(data.Array, data.Offset, 8);
- var nanoseconds = unchecked((uint)intValue);
- value = CustomMessagePackExtensionTypeHandler.UnixEpoch.AddSeconds(longValue).AddTicks(nanoseconds / CustomMessagePackExtensionTypeHandler.NanosecondsPerTick);
- return true;
- }
- default:
- throw new Exception($"Length of extension was {data.Count}. Either 4, 8 or 12 were expected.");
- }
- default:
- return false;
- }
- }
-
- public override bool TryWrite(object value, out sbyte type, ref ArraySegment<byte> data)
- {
- if (value == null)
- {
- type = 0;
- return false;
- }
- else if (value is DateTime)
- {
- type = EXTENSION_TYPE_DATE_TIME;
- var dateTime = (DateTime)(object)value;
- // The spec requires UTC. Convert to UTC if we're sure the value was expressed as Local time.
- // If it's Unspecified, we want to leave it alone since .NET will change the value when we convert
- // and we simply don't know, so we should leave it as-is.
- if (dateTime.Kind == DateTimeKind.Local)
- {
- dateTime = dateTime.ToUniversalTime();
- }
- var secondsSinceBclEpoch = dateTime.Ticks / TimeSpan.TicksPerSecond;
- var seconds = secondsSinceBclEpoch - CustomMessagePackExtensionTypeHandler.BclSecondsAtUnixEpoch;
- var nanoseconds = (dateTime.Ticks % TimeSpan.TicksPerSecond) * CustomMessagePackExtensionTypeHandler.NanosecondsPerTick;
- if ((seconds >> 34) == 0)
- {
- var data64 = unchecked((ulong)((nanoseconds << 34) | seconds));
- if ((data64 & 0xffffffff00000000L) == 0)
- {
- // timestamp 32(seconds in 32-bit unsigned int)
- var data32 = (UInt32)data64;
- const int TIMESTAMP_SIZE = 4;
- if (data.Array == null || data.Count < TIMESTAMP_SIZE)
- data = new ArraySegment<byte>(new byte[TIMESTAMP_SIZE]);
- CopyBytesImpl(data32, 4, data.Array, data.Offset);
- if (data.Count != DATE_TIME_SIZE)
- data = new ArraySegment<byte>(data.Array, data.Offset, DATE_TIME_SIZE);
- }
- else
- {
- // timestamp 64(nanoseconds in 30-bit unsigned int | seconds in 34-bit unsigned int)
- const int TIMESTAMP_SIZE = 8;
- if (data.Array == null || data.Count < TIMESTAMP_SIZE)
- data = new ArraySegment<byte>(new byte[TIMESTAMP_SIZE]);
- CopyBytesImpl(unchecked((long)data64), 8, data.Array, data.Offset);
- if (data.Count != DATE_TIME_SIZE)
- data = new ArraySegment<byte>(data.Array, data.Offset, DATE_TIME_SIZE);
- }
- }
- else
- {
- // timestamp 96( nanoseconds in 32-bit unsigned int | seconds in 64-bit signed int )
- const int TIMESTAMP_SIZE = 12;
- if (data.Array == null || data.Count < TIMESTAMP_SIZE)
- data = new ArraySegment<byte>(new byte[TIMESTAMP_SIZE]);
- CopyBytesImpl((uint)nanoseconds, 4, data.Array, data.Offset);
- CopyBytesImpl(seconds, 8, data.Array, data.Offset + 4);
- if (data.Count != DATE_TIME_SIZE)
- data = new ArraySegment<byte>(data.Array, data.Offset, DATE_TIME_SIZE);
- }
- return true;
- }
- type = default(sbyte);
- return false;
- }
- private void CopyBytesImpl(long value, int bytes, byte[] buffer, int index)
- {
- var endOffset = index + bytes - 1;
- for (var i = 0; i < bytes; i++)
- {
- buffer[endOffset - i] = unchecked((byte)(value & 0xff));
- value = value >> 8;
- }
- }
- private long FromBytes(byte[] buffer, int startIndex, int bytesToConvert)
- {
- long ret = 0;
- for (var i = 0; i < bytesToConvert; i++)
- {
- ret = unchecked((ret << 8) | buffer[startIndex + i]);
- }
- return ret;
- }
- }
- // https://github.com/neuecc/MessagePack-CSharp/blob/13c299a5172c60154bae53395612af194c02d286/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Unity/Formatters.cs#L15
- public sealed class Vector2Serializer : TypeSerializer
- {
- public override Type SerializedType { get { return typeof(Vector2); } }
- public override object Deserialize(IJsonReader reader)
- {
- if (reader == null) throw new ArgumentNullException("reader");
- if (reader.Token == JsonToken.Null)
- return null;
- var value = new Vector2();
- reader.ReadArrayBegin();
- int idx = 0;
- while (reader.Token != JsonToken.EndOfArray)
- value[idx++] = reader.ReadSingle();
- reader.ReadArrayEnd(nextToken: false);
- return value;
- }
- public override void Serialize(IJsonWriter writer, object value)
- {
- if (writer == null) throw new ArgumentNullException("writer");
- if (value == null) throw new ArgumentNullException("value");
- var vector2 = (Vector2)value;
- writer.WriteArrayBegin(2);
- writer.Write(vector2.x);
- writer.Write(vector2.y);
- writer.WriteArrayEnd();
- }
- }
- // https://github.com/neuecc/MessagePack-CSharp/blob/13c299a5172c60154bae53395612af194c02d286/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Unity/Formatters.cs#L56
- public sealed class Vector3Serializer : TypeSerializer
- {
- public override Type SerializedType { get { return typeof(Vector3); } }
- public override object Deserialize(IJsonReader reader)
- {
- if (reader == null) throw new ArgumentNullException("reader");
- if (reader.Token == JsonToken.Null)
- return null;
- var value = new Vector3();
- reader.ReadArrayBegin();
- int idx = 0;
- while (reader.Token != JsonToken.EndOfArray)
- value[idx++] = reader.ReadSingle();
- reader.ReadArrayEnd(nextToken: false);
- return value;
- }
- public override void Serialize(IJsonWriter writer, object value)
- {
- if (writer == null) throw new ArgumentNullException("writer");
- if (value == null) throw new ArgumentNullException("value");
- var vector3 = (Vector3)value;
- writer.WriteArrayBegin(3);
- writer.Write(vector3.x);
- writer.Write(vector3.y);
- writer.Write(vector3.z);
- writer.WriteArrayEnd();
- }
- }
- // https://github.com/neuecc/MessagePack-CSharp/blob/13c299a5172c60154bae53395612af194c02d286/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Unity/Formatters.cs#L102
- public sealed class Vector4Serializer : TypeSerializer
- {
- public override Type SerializedType { get { return typeof(Vector4); } }
- public override object Deserialize(IJsonReader reader)
- {
- if (reader == null) throw new ArgumentNullException("reader");
- if (reader.Token == JsonToken.Null)
- return null;
- var value = new Vector4();
- reader.ReadArrayBegin();
- int idx = 0;
- while (reader.Token != JsonToken.EndOfArray)
- value[idx++] = reader.ReadSingle();
- reader.ReadArrayEnd(nextToken: false);
- return value;
- }
- public override void Serialize(IJsonWriter writer, object value)
- {
- if (writer == null) throw new ArgumentNullException("writer");
- if (value == null) throw new ArgumentNullException("value");
- var vector4 = (Vector4)value;
- writer.WriteArrayBegin(4);
- writer.Write(vector4.x);
- writer.Write(vector4.y);
- writer.Write(vector4.z);
- writer.Write(vector4.z);
- writer.WriteArrayEnd();
- }
- }
- }
- #endif
|