Explorar el Código

添加Json.net,將protobuf-net.dll換成源码

mongodb的bson序列化在ios上可能有问题,添加json.net用于替换客户端json序列化方式,protobuf-net.dll在ios上有问题无法序列化,改为源码方式可解决
Lucky hace 8 años
padre
commit
ebb5617a65
Se han modificado 100 ficheros con 15433 adiciones y 156 borrados
  1. BIN
      Unity/Assets/Plugins/Newtonsoft.Json.dll
  2. 34 0
      Unity/Assets/Plugins/Newtonsoft.Json.dll.meta
  3. BIN
      Unity/Assets/Plugins/protobuf-net.dll
  4. 0 138
      Unity/Assets/Plugins/protobuf-net.dll.meta
  5. 546 0
      Unity/Assets/Plugins/protobuf-net/BclHelpers.cs
  6. 12 0
      Unity/Assets/Plugins/protobuf-net/BclHelpers.cs.meta
  7. 73 0
      Unity/Assets/Plugins/protobuf-net/BufferExtension.cs
  8. 12 0
      Unity/Assets/Plugins/protobuf-net/BufferExtension.cs.meta
  9. 103 0
      Unity/Assets/Plugins/protobuf-net/BufferPool.cs
  10. 12 0
      Unity/Assets/Plugins/protobuf-net/BufferPool.cs.meta
  11. 33 0
      Unity/Assets/Plugins/protobuf-net/CallbackAttributes.cs
  12. 12 0
      Unity/Assets/Plugins/protobuf-net/CallbackAttributes.cs.meta
  13. 3 3
      Unity/Assets/Plugins/protobuf-net/Compiler.meta
  14. 1451 0
      Unity/Assets/Plugins/protobuf-net/Compiler/CompilerContext.cs
  15. 12 0
      Unity/Assets/Plugins/protobuf-net/Compiler/CompilerContext.cs.meta
  16. 7 0
      Unity/Assets/Plugins/protobuf-net/Compiler/CompilerDelegates.cs
  17. 12 0
      Unity/Assets/Plugins/protobuf-net/Compiler/CompilerDelegates.cs.meta
  18. 70 0
      Unity/Assets/Plugins/protobuf-net/Compiler/Local.cs
  19. 12 0
      Unity/Assets/Plugins/protobuf-net/Compiler/Local.cs.meta
  20. 42 0
      Unity/Assets/Plugins/protobuf-net/DataFormat.cs
  21. 12 0
      Unity/Assets/Plugins/protobuf-net/DataFormat.cs.meta
  22. 286 0
      Unity/Assets/Plugins/protobuf-net/Extensible.cs
  23. 12 0
      Unity/Assets/Plugins/protobuf-net/Extensible.cs.meta
  24. 151 0
      Unity/Assets/Plugins/protobuf-net/ExtensibleUtil.cs
  25. 12 0
      Unity/Assets/Plugins/protobuf-net/ExtensibleUtil.cs.meta
  26. BIN
      Unity/Assets/Plugins/protobuf-net/GlobalSuppressions.cs
  27. 12 0
      Unity/Assets/Plugins/protobuf-net/GlobalSuppressions.cs.meta
  28. 601 0
      Unity/Assets/Plugins/protobuf-net/Helpers.cs
  29. 12 0
      Unity/Assets/Plugins/protobuf-net/Helpers.cs.meta
  30. 27 0
      Unity/Assets/Plugins/protobuf-net/IExtensible.cs
  31. 12 0
      Unity/Assets/Plugins/protobuf-net/IExtensible.cs.meta
  32. 47 0
      Unity/Assets/Plugins/protobuf-net/IExtension.cs
  33. 12 0
      Unity/Assets/Plugins/protobuf-net/IExtension.cs.meta
  34. 31 0
      Unity/Assets/Plugins/protobuf-net/ImplicitFields.cs
  35. 12 0
      Unity/Assets/Plugins/protobuf-net/ImplicitFields.cs.meta
  36. 46 0
      Unity/Assets/Plugins/protobuf-net/KeyValuePairProxy.cs
  37. 12 0
      Unity/Assets/Plugins/protobuf-net/KeyValuePairProxy.cs.meta
  38. 3 3
      Unity/Assets/Plugins/protobuf-net/Meta.meta
  39. 191 0
      Unity/Assets/Plugins/protobuf-net/Meta/AttributeMap.cs
  40. 12 0
      Unity/Assets/Plugins/protobuf-net/Meta/AttributeMap.cs.meta
  41. 246 0
      Unity/Assets/Plugins/protobuf-net/Meta/BasicList.cs
  42. 12 0
      Unity/Assets/Plugins/protobuf-net/Meta/BasicList.cs.meta
  43. 107 0
      Unity/Assets/Plugins/protobuf-net/Meta/CallbackSet.cs
  44. 12 0
      Unity/Assets/Plugins/protobuf-net/Meta/CallbackSet.cs.meta
  45. 1858 0
      Unity/Assets/Plugins/protobuf-net/Meta/MetaType.cs
  46. 12 0
      Unity/Assets/Plugins/protobuf-net/Meta/MetaType.cs.meta
  47. 2005 0
      Unity/Assets/Plugins/protobuf-net/Meta/RuntimeTypeModel.cs
  48. 12 0
      Unity/Assets/Plugins/protobuf-net/Meta/RuntimeTypeModel.cs.meta
  49. 82 0
      Unity/Assets/Plugins/protobuf-net/Meta/SubType.cs
  50. 12 0
      Unity/Assets/Plugins/protobuf-net/Meta/SubType.cs.meta
  51. 62 0
      Unity/Assets/Plugins/protobuf-net/Meta/TypeFormatEventArgs.cs
  52. 12 0
      Unity/Assets/Plugins/protobuf-net/Meta/TypeFormatEventArgs.cs.meta
  53. 1624 0
      Unity/Assets/Plugins/protobuf-net/Meta/TypeModel.cs
  54. 12 0
      Unity/Assets/Plugins/protobuf-net/Meta/TypeModel.cs.meta
  55. 635 0
      Unity/Assets/Plugins/protobuf-net/Meta/ValueMember.cs
  56. 12 0
      Unity/Assets/Plugins/protobuf-net/Meta/ValueMember.cs.meta
  57. 246 0
      Unity/Assets/Plugins/protobuf-net/NetObjectCache.cs
  58. 12 0
      Unity/Assets/Plugins/protobuf-net/NetObjectCache.cs.meta
  59. 26 0
      Unity/Assets/Plugins/protobuf-net/PrefixStyle.cs
  60. 12 0
      Unity/Assets/Plugins/protobuf-net/PrefixStyle.cs.meta
  61. 0 9
      Unity/Assets/Plugins/protobuf-net/Properties.meta
  62. 165 0
      Unity/Assets/Plugins/protobuf-net/ProtoContractAttribute.cs
  63. 12 0
      Unity/Assets/Plugins/protobuf-net/ProtoContractAttribute.cs.meta
  64. 13 0
      Unity/Assets/Plugins/protobuf-net/ProtoConverterAttribute.cs
  65. 12 0
      Unity/Assets/Plugins/protobuf-net/ProtoConverterAttribute.cs.meta
  66. 37 0
      Unity/Assets/Plugins/protobuf-net/ProtoEnumAttribute.cs
  67. 12 0
      Unity/Assets/Plugins/protobuf-net/ProtoEnumAttribute.cs.meta
  68. 30 0
      Unity/Assets/Plugins/protobuf-net/ProtoException.cs
  69. 12 0
      Unity/Assets/Plugins/protobuf-net/ProtoException.cs.meta
  70. 40 0
      Unity/Assets/Plugins/protobuf-net/ProtoIgnoreAttribute.cs
  71. 12 0
      Unity/Assets/Plugins/protobuf-net/ProtoIgnoreAttribute.cs.meta
  72. 78 0
      Unity/Assets/Plugins/protobuf-net/ProtoIncludeAttribute.cs
  73. 12 0
      Unity/Assets/Plugins/protobuf-net/ProtoIncludeAttribute.cs.meta
  74. 231 0
      Unity/Assets/Plugins/protobuf-net/ProtoMemberAttribute.cs
  75. 12 0
      Unity/Assets/Plugins/protobuf-net/ProtoMemberAttribute.cs.meta
  76. 1414 0
      Unity/Assets/Plugins/protobuf-net/ProtoReader.cs
  77. 12 0
      Unity/Assets/Plugins/protobuf-net/ProtoReader.cs.meta
  78. 951 0
      Unity/Assets/Plugins/protobuf-net/ProtoWriter.cs
  79. 12 0
      Unity/Assets/Plugins/protobuf-net/ProtoWriter.cs.meta
  80. 73 0
      Unity/Assets/Plugins/protobuf-net/SerializationContext.cs
  81. 12 0
      Unity/Assets/Plugins/protobuf-net/SerializationContext.cs.meta
  82. 530 0
      Unity/Assets/Plugins/protobuf-net/Serializer.cs
  83. 12 0
      Unity/Assets/Plugins/protobuf-net/Serializer.cs.meta
  84. 3 3
      Unity/Assets/Plugins/protobuf-net/Serializers.meta
  85. 271 0
      Unity/Assets/Plugins/protobuf-net/Serializers/ArrayDecorator.cs
  86. 12 0
      Unity/Assets/Plugins/protobuf-net/Serializers/ArrayDecorator.cs.meta
  87. 64 0
      Unity/Assets/Plugins/protobuf-net/Serializers/BlobSerializer.cs
  88. 12 0
      Unity/Assets/Plugins/protobuf-net/Serializers/BlobSerializer.cs.meta
  89. 57 0
      Unity/Assets/Plugins/protobuf-net/Serializers/BooleanSerializer.cs
  90. 12 0
      Unity/Assets/Plugins/protobuf-net/Serializers/BooleanSerializer.cs.meta
  91. 54 0
      Unity/Assets/Plugins/protobuf-net/Serializers/ByteSerializer.cs
  92. 12 0
      Unity/Assets/Plugins/protobuf-net/Serializers/ByteSerializer.cs.meta
  93. 44 0
      Unity/Assets/Plugins/protobuf-net/Serializers/CharSerializer.cs
  94. 12 0
      Unity/Assets/Plugins/protobuf-net/Serializers/CharSerializer.cs.meta
  95. 78 0
      Unity/Assets/Plugins/protobuf-net/Serializers/CompiledSerializer.cs
  96. 12 0
      Unity/Assets/Plugins/protobuf-net/Serializers/CompiledSerializer.cs.meta
  97. 55 0
      Unity/Assets/Plugins/protobuf-net/Serializers/DateTimeSerializer.cs
  98. 12 0
      Unity/Assets/Plugins/protobuf-net/Serializers/DateTimeSerializer.cs.meta
  99. 57 0
      Unity/Assets/Plugins/protobuf-net/Serializers/DecimalSerializer.cs
  100. 12 0
      Unity/Assets/Plugins/protobuf-net/Serializers/DecimalSerializer.cs.meta

BIN
Unity/Assets/Plugins/Newtonsoft.Json.dll


+ 34 - 0
Unity/Assets/Plugins/Newtonsoft.Json.dll.meta

@@ -0,0 +1,34 @@
+fileFormatVersion: 2
+guid: 528015a69143a8e4cb7073828e325afd
+timeCreated: 1515924057
+licenseType: Pro
+PluginImporter:
+  serializedVersion: 2
+  iconMap: {}
+  executionOrder: {}
+  isPreloaded: 0
+  isOverridable: 0
+  platformData:
+    data:
+      first:
+        Any: 
+      second:
+        enabled: 1
+        settings: {}
+    data:
+      first:
+        Editor: Editor
+      second:
+        enabled: 0
+        settings:
+          DefaultValueInitialized: true
+    data:
+      first:
+        Windows Store Apps: WindowsStoreApps
+      second:
+        enabled: 0
+        settings:
+          CPU: AnyCPU
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Unity/Assets/Plugins/protobuf-net.dll


+ 0 - 138
Unity/Assets/Plugins/protobuf-net.dll.meta

@@ -1,138 +0,0 @@
-fileFormatVersion: 2
-guid: a0c7b591a8070ed43b5032fbc7cb6c5f
-timeCreated: 1513686555
-licenseType: Free
-PluginImporter:
-  serializedVersion: 2
-  iconMap: {}
-  executionOrder: {}
-  isPreloaded: 0
-  isOverridable: 0
-  platformData:
-    data:
-      first:
-        '': Any
-      second:
-        enabled: 0
-        settings:
-          Exclude Android: 0
-          Exclude Editor: 0
-          Exclude Linux: 0
-          Exclude Linux64: 0
-          Exclude LinuxUniversal: 0
-          Exclude OSXIntel: 0
-          Exclude OSXIntel64: 0
-          Exclude OSXUniversal: 0
-          Exclude Win: 0
-          Exclude Win64: 0
-          Exclude iOS: 0
-    data:
-      first:
-        Android: Android
-      second:
-        enabled: 1
-        settings:
-          CPU: ARMv7
-    data:
-      first:
-        Any: 
-      second:
-        enabled: 1
-        settings: {}
-    data:
-      first:
-        Editor: Editor
-      second:
-        enabled: 1
-        settings:
-          CPU: AnyCPU
-          DefaultValueInitialized: true
-          OS: AnyOS
-    data:
-      first:
-        Facebook: Win
-      second:
-        enabled: 0
-        settings:
-          CPU: AnyCPU
-    data:
-      first:
-        Facebook: Win64
-      second:
-        enabled: 0
-        settings:
-          CPU: AnyCPU
-    data:
-      first:
-        Standalone: Linux
-      second:
-        enabled: 1
-        settings:
-          CPU: x86
-    data:
-      first:
-        Standalone: Linux64
-      second:
-        enabled: 1
-        settings:
-          CPU: x86_64
-    data:
-      first:
-        Standalone: LinuxUniversal
-      second:
-        enabled: 1
-        settings:
-          CPU: AnyCPU
-    data:
-      first:
-        Standalone: OSXIntel
-      second:
-        enabled: 1
-        settings:
-          CPU: AnyCPU
-    data:
-      first:
-        Standalone: OSXIntel64
-      second:
-        enabled: 1
-        settings:
-          CPU: AnyCPU
-    data:
-      first:
-        Standalone: OSXUniversal
-      second:
-        enabled: 1
-        settings:
-          CPU: AnyCPU
-    data:
-      first:
-        Standalone: Win
-      second:
-        enabled: 1
-        settings:
-          CPU: AnyCPU
-    data:
-      first:
-        Standalone: Win64
-      second:
-        enabled: 1
-        settings:
-          CPU: AnyCPU
-    data:
-      first:
-        Windows Store Apps: WindowsStoreApps
-      second:
-        enabled: 0
-        settings:
-          CPU: AnyCPU
-    data:
-      first:
-        iPhone: iOS
-      second:
-        enabled: 1
-        settings:
-          CompileFlags: 
-          FrameworkDependencies: 
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 

+ 546 - 0
Unity/Assets/Plugins/protobuf-net/BclHelpers.cs

@@ -0,0 +1,546 @@
+using System;
+using System.Reflection;
+namespace ProtoBuf
+{
+    internal enum TimeSpanScale
+    {
+        Days = 0,
+        Hours = 1,
+        Minutes = 2,
+        Seconds = 3,
+        Milliseconds = 4,
+        Ticks = 5,
+
+        MinMax = 15
+    }
+
+    /// <summary>
+    /// Provides support for common .NET types that do not have a direct representation
+    /// in protobuf, using the definitions from bcl.proto
+    /// </summary>
+    public
+#if FX11
+    sealed
+#else
+    static
+#endif
+        class BclHelpers
+    {
+        /// <summary>
+        /// Creates a new instance of the specified type, bypassing the constructor.
+        /// </summary>
+        /// <param name="type">The type to create</param>
+        /// <returns>The new instance</returns>
+        /// <exception cref="NotSupportedException">If the platform does not support constructor-skipping</exception>
+        public static object GetUninitializedObject(Type type)
+        {
+#if PLAT_BINARYFORMATTER && !(WINRT || PHONE8)
+            return System.Runtime.Serialization.FormatterServices.GetUninitializedObject(type);
+#else
+            throw new NotSupportedException("Constructor-skipping is not supported on this platform");
+#endif
+        }
+#if FX11
+        private BclHelpers() { } // not a static class for C# 1.2 reasons
+#endif
+        const int FieldTimeSpanValue = 0x01, FieldTimeSpanScale = 0x02;
+        
+        internal static readonly DateTime EpochOrigin = new DateTime(1970, 1, 1, 0, 0, 0, 0);
+
+        /// <summary>
+        /// Writes a TimeSpan to a protobuf stream
+        /// </summary>
+        public static void WriteTimeSpan(TimeSpan timeSpan, ProtoWriter dest)
+        {
+            if (dest == null) throw new ArgumentNullException("dest");
+            long value;
+            switch(dest.WireType)
+            {
+                case WireType.String:
+                case WireType.StartGroup:
+                    TimeSpanScale scale;
+                    value = timeSpan.Ticks;
+                    if (timeSpan == TimeSpan.MaxValue)
+                    {
+                        value = 1;
+                        scale = TimeSpanScale.MinMax;
+                    }
+                    else if (timeSpan == TimeSpan.MinValue)
+                    {
+                        value = -1;
+                        scale = TimeSpanScale.MinMax;
+                    }
+                    else if (value % TimeSpan.TicksPerDay == 0)
+                    {
+                        scale = TimeSpanScale.Days;
+                        value /= TimeSpan.TicksPerDay;
+                    }
+                    else if (value % TimeSpan.TicksPerHour == 0)
+                    {
+                        scale = TimeSpanScale.Hours;
+                        value /= TimeSpan.TicksPerHour;
+                    }
+                    else if (value % TimeSpan.TicksPerMinute == 0)
+                    {
+                        scale = TimeSpanScale.Minutes;
+                        value /= TimeSpan.TicksPerMinute;
+                    }
+                    else if (value % TimeSpan.TicksPerSecond == 0)
+                    {
+                        scale = TimeSpanScale.Seconds;
+                        value /= TimeSpan.TicksPerSecond;
+                    }
+                    else if (value % TimeSpan.TicksPerMillisecond == 0)
+                    {
+                        scale = TimeSpanScale.Milliseconds;
+                        value /= TimeSpan.TicksPerMillisecond;
+                    }
+                    else
+                    {
+                        scale = TimeSpanScale.Ticks;
+                    }
+
+                    SubItemToken token = ProtoWriter.StartSubItem(null, dest);
+            
+                    if(value != 0) {
+                        ProtoWriter.WriteFieldHeader(FieldTimeSpanValue, WireType.SignedVariant, dest);
+                        ProtoWriter.WriteInt64(value, dest);
+                    }
+                    if(scale != TimeSpanScale.Days) {
+                        ProtoWriter.WriteFieldHeader(FieldTimeSpanScale, WireType.Variant, dest);
+                        ProtoWriter.WriteInt32((int)scale, dest);
+                    }
+                    ProtoWriter.EndSubItem(token, dest);
+                    break;
+                case WireType.Fixed64:
+                    ProtoWriter.WriteInt64(timeSpan.Ticks, dest);
+                    break;
+                default:
+                    throw new ProtoException("Unexpected wire-type: " + dest.WireType.ToString());
+            }
+        }
+        /// <summary>
+        /// Parses a TimeSpan from a protobuf stream
+        /// </summary>        
+        public static TimeSpan ReadTimeSpan(ProtoReader source)
+        {
+            long ticks = ReadTimeSpanTicks(source);
+            if (ticks == long.MinValue) return TimeSpan.MinValue;
+            if (ticks == long.MaxValue) return TimeSpan.MaxValue;
+            return TimeSpan.FromTicks(ticks);
+        }
+        /// <summary>
+        /// Parses a DateTime from a protobuf stream
+        /// </summary>
+        public static DateTime ReadDateTime(ProtoReader source)
+        {
+            long ticks = ReadTimeSpanTicks(source);
+            if (ticks == long.MinValue) return DateTime.MinValue;
+            if (ticks == long.MaxValue) return DateTime.MaxValue;
+            return EpochOrigin.AddTicks(ticks);
+        }
+        /// <summary>
+        /// Writes a DateTime to a protobuf stream
+        /// </summary>
+        public static void WriteDateTime(DateTime value, ProtoWriter dest)
+        {
+            if (dest == null) throw new ArgumentNullException("dest");
+            TimeSpan delta;
+            switch (dest.WireType)
+            {
+                case WireType.StartGroup:
+                case WireType.String:
+                    if (value == DateTime.MaxValue)
+                    {
+                        delta = TimeSpan.MaxValue;
+                    }
+                    else if (value == DateTime.MinValue)
+                    {
+                        delta = TimeSpan.MinValue;
+                    }
+                    else
+                    {
+                        delta = value - EpochOrigin;
+                    }
+                    break;
+                default:
+                    delta = value - EpochOrigin;
+                    break;
+            }
+            WriteTimeSpan(delta, dest);
+        }
+
+        private static long ReadTimeSpanTicks(ProtoReader source) {
+            switch (source.WireType)
+            {
+                case WireType.String:
+                case WireType.StartGroup:
+                    SubItemToken token = ProtoReader.StartSubItem(source);
+                    int fieldNumber;
+                    TimeSpanScale scale = TimeSpanScale.Days;
+                    long value = 0;
+                    while ((fieldNumber = source.ReadFieldHeader()) > 0)
+                    {
+                        switch (fieldNumber)
+                        {
+                            case FieldTimeSpanScale:
+                                scale = (TimeSpanScale)source.ReadInt32();
+                                break;
+                            case FieldTimeSpanValue:
+                                source.Assert(WireType.SignedVariant);
+                                value = source.ReadInt64();
+                                break;
+                            default:
+                                source.SkipField();
+                                break;
+                        }
+                    }
+                    ProtoReader.EndSubItem(token, source);
+                    switch (scale)
+                    {
+                        case TimeSpanScale.Days:
+                            return value * TimeSpan.TicksPerDay;
+                        case TimeSpanScale.Hours:
+                            return value * TimeSpan.TicksPerHour;
+                        case TimeSpanScale.Minutes:
+                            return value * TimeSpan.TicksPerMinute;
+                        case TimeSpanScale.Seconds:
+                            return value * TimeSpan.TicksPerSecond;
+                        case TimeSpanScale.Milliseconds:
+                            return value * TimeSpan.TicksPerMillisecond;
+                        case TimeSpanScale.Ticks:
+                            return value;
+                        case TimeSpanScale.MinMax:
+                            switch (value)
+                            {
+                                case 1: return long.MaxValue;
+                                case -1: return long.MinValue;
+                                default: throw new ProtoException("Unknown min/max value: " + value.ToString());
+                            }
+                        default:
+                            throw new ProtoException("Unknown timescale: " + scale.ToString());
+                    }
+                case WireType.Fixed64:
+                    return source.ReadInt64();
+                default:
+                    throw new ProtoException("Unexpected wire-type: " + source.WireType.ToString());
+            }
+        }
+
+        const int FieldDecimalLow = 0x01, FieldDecimalHigh = 0x02, FieldDecimalSignScale = 0x03;
+
+        /// <summary>
+        /// Parses a decimal from a protobuf stream
+        /// </summary>
+        public static decimal ReadDecimal(ProtoReader reader)
+        {
+            ulong low = 0;
+            uint high = 0;
+            uint signScale = 0;
+
+            int fieldNumber;
+            SubItemToken token = ProtoReader.StartSubItem(reader);
+            while ((fieldNumber = reader.ReadFieldHeader()) > 0)
+            {
+                switch (fieldNumber)
+                {
+                    case FieldDecimalLow: low = reader.ReadUInt64(); break;
+                    case FieldDecimalHigh: high = reader.ReadUInt32(); break;
+                    case FieldDecimalSignScale: signScale = reader.ReadUInt32(); break;
+                    default: reader.SkipField(); break;
+                }
+                
+            }
+            ProtoReader.EndSubItem(token, reader);
+
+            if (low == 0 && high == 0) return decimal.Zero;
+
+            int lo = (int)(low & 0xFFFFFFFFL),
+                mid = (int)((low >> 32) & 0xFFFFFFFFL),
+                hi = (int)high;
+            bool isNeg = (signScale & 0x0001) == 0x0001;
+            byte scale = (byte)((signScale & 0x01FE) >> 1);
+            return new decimal(lo, mid, hi, isNeg, scale);
+        }
+        /// <summary>
+        /// Writes a decimal to a protobuf stream
+        /// </summary>
+        public static void WriteDecimal(decimal value, ProtoWriter writer)
+        {
+            int[] bits = decimal.GetBits(value);
+            ulong a = ((ulong)bits[1]) << 32, b = ((ulong)bits[0]) & 0xFFFFFFFFL;
+            ulong low = a | b;
+            uint high = (uint)bits[2];
+            uint signScale = (uint)(((bits[3] >> 15) & 0x01FE) | ((bits[3] >> 31) & 0x0001));
+
+            SubItemToken token = ProtoWriter.StartSubItem(null, writer);
+            if (low != 0) {
+                ProtoWriter.WriteFieldHeader(FieldDecimalLow, WireType.Variant, writer);
+                ProtoWriter.WriteUInt64(low, writer);
+            }
+            if (high != 0)
+            {
+                ProtoWriter.WriteFieldHeader(FieldDecimalHigh, WireType.Variant, writer);
+                ProtoWriter.WriteUInt32(high, writer);
+            }
+            if (signScale != 0)
+            {
+                ProtoWriter.WriteFieldHeader(FieldDecimalSignScale, WireType.Variant, writer);
+                ProtoWriter.WriteUInt32(signScale, writer);
+            }
+            ProtoWriter.EndSubItem(token, writer);
+        }
+
+        const int FieldGuidLow = 1, FieldGuidHigh = 2;
+        /// <summary>
+        /// Writes a Guid to a protobuf stream
+        /// </summary>        
+        public static void WriteGuid(Guid value, ProtoWriter dest)
+        {
+            byte[] blob = value.ToByteArray();
+
+            SubItemToken token = ProtoWriter.StartSubItem(null, dest);
+            if (value != Guid.Empty)
+            {
+                ProtoWriter.WriteFieldHeader(FieldGuidLow, WireType.Fixed64, dest);
+                ProtoWriter.WriteBytes(blob, 0, 8, dest);
+                ProtoWriter.WriteFieldHeader(FieldGuidHigh, WireType.Fixed64, dest);
+                ProtoWriter.WriteBytes(blob, 8, 8, dest);
+            }
+            ProtoWriter.EndSubItem(token, dest);
+        }
+        /// <summary>
+        /// Parses a Guid from a protobuf stream
+        /// </summary>
+        public static Guid ReadGuid(ProtoReader source)
+        {
+            ulong low = 0, high = 0;
+            int fieldNumber;
+            SubItemToken token = ProtoReader.StartSubItem(source);
+            while ((fieldNumber = source.ReadFieldHeader()) > 0)
+            {
+                switch (fieldNumber)
+                {
+                    case FieldGuidLow: low = source.ReadUInt64(); break;
+                    case FieldGuidHigh: high = source.ReadUInt64(); break;
+                    default: source.SkipField(); break;
+                }
+            }
+            ProtoReader.EndSubItem(token, source);
+            if(low == 0 && high == 0) return Guid.Empty;
+            uint a = (uint)(low >> 32), b = (uint)low, c = (uint)(high >> 32), d= (uint)high;
+            return new Guid((int)b, (short)a, (short)(a >> 16), 
+                (byte)d, (byte)(d >> 8), (byte)(d >> 16), (byte)(d >> 24),
+                (byte)c, (byte)(c >> 8), (byte)(c >> 16), (byte)(c >> 24));
+            
+        }
+
+
+        private const int
+            FieldExistingObjectKey = 1,
+            FieldNewObjectKey = 2,
+            FieldExistingTypeKey = 3,
+            FieldNewTypeKey = 4,
+            FieldTypeName = 8,
+            FieldObject = 10;
+        /// <summary>
+        /// Optional behaviours that introduce .NET-specific functionality
+        /// </summary>
+        [Flags]
+        public enum NetObjectOptions : byte
+        {
+            /// <summary>
+            /// No special behaviour
+            /// </summary>
+            None = 0,
+            /// <summary>
+            /// Enables full object-tracking/full-graph support.
+            /// </summary>
+            AsReference = 1,
+            /// <summary>
+            /// Embeds the type information into the stream, allowing usage with types not known in advance.
+            /// </summary>
+            DynamicType = 2,
+            /// <summary>
+            /// If false, the constructor for the type is bypassed during deserialization, meaning any field initializers
+            /// or other initialization code is skipped.
+            /// </summary>
+            UseConstructor = 4,
+            /// <summary>
+            /// Should the object index be reserved, rather than creating an object promptly
+            /// </summary>
+            LateSet = 8
+        }
+        /// <summary>
+        /// Reads an *implementation specific* bundled .NET object, including (as options) type-metadata, identity/re-use, etc.
+        /// </summary>
+        public static object ReadNetObject(object value, ProtoReader source, int key, Type type, NetObjectOptions options)
+        {
+#if FEAT_IKVM
+            throw new NotSupportedException();
+#else
+            SubItemToken token = ProtoReader.StartSubItem(source);
+            int fieldNumber;
+            int newObjectKey = -1, newTypeKey = -1, tmp;
+            while ((fieldNumber = source.ReadFieldHeader()) > 0)
+            {
+                switch (fieldNumber)
+                {
+                    case FieldExistingObjectKey:
+                        tmp = source.ReadInt32();
+                        value = source.NetCache.GetKeyedObject(tmp);
+                        break;
+                    case FieldNewObjectKey:
+                        newObjectKey = source.ReadInt32();
+                        break;
+                    case FieldExistingTypeKey:
+                        tmp = source.ReadInt32();
+                        type = (Type)source.NetCache.GetKeyedObject(tmp);
+                        key = source.GetTypeKey(ref type);
+                        break;
+                    case FieldNewTypeKey:
+                        newTypeKey = source.ReadInt32();
+                        break;
+                    case FieldTypeName:
+                        string typeName = source.ReadString();
+                        type = source.DeserializeType(typeName);
+                        if(type == null)
+                        {
+                            throw new ProtoException("Unable to resolve type: " + typeName + " (you can use the TypeModel.DynamicTypeFormatting event to provide a custom mapping)");
+                        }
+                        if (type == typeof(string))
+                        {
+                            key = -1;
+                        }
+                        else
+                        {
+                            key = source.GetTypeKey(ref type);
+                            if (key < 0)
+                                throw new InvalidOperationException("Dynamic type is not a contract-type: " + type.Name);
+                        }
+                        break;
+                    case FieldObject:
+                        bool isString = type == typeof(string);
+                        bool wasNull = value == null;
+                        bool lateSet = wasNull && (isString || ((options & NetObjectOptions.LateSet) != 0));
+                        
+                        if (newObjectKey >= 0 && !lateSet)
+                        {
+                            if (value == null)
+                            {
+                                source.TrapNextObject(newObjectKey);
+                            }
+                            else
+                            {
+                                source.NetCache.SetKeyedObject(newObjectKey, value);
+                            }
+                            if (newTypeKey >= 0) source.NetCache.SetKeyedObject(newTypeKey, type);
+                        }
+                        object oldValue = value;
+                        if (isString)
+                        {
+                            value = source.ReadString();
+                        }
+                        else
+                        {
+                            value = ProtoReader.ReadTypedObject(oldValue, key, source, type);
+                        }
+                        
+                        if (newObjectKey >= 0)
+                        {
+                            if(wasNull && !lateSet)
+                            { // this both ensures (via exception) that it *was* set, and makes sure we don't shout
+                                // about changed references
+                                oldValue = source.NetCache.GetKeyedObject(newObjectKey);
+                            }
+                            if (lateSet)
+                            {
+                                source.NetCache.SetKeyedObject(newObjectKey, value);
+                                if (newTypeKey >= 0) source.NetCache.SetKeyedObject(newTypeKey, type);
+                            }
+                        }
+                        if (newObjectKey >= 0 && !lateSet && !ReferenceEquals(oldValue, value))
+                        {
+                            throw new ProtoException("A reference-tracked object changed reference during deserialization");
+                        }
+                        if (newObjectKey < 0 && newTypeKey >= 0)
+                        {  // have a new type, but not a new object
+                            source.NetCache.SetKeyedObject(newTypeKey, type);
+                        }
+                        break;
+                    default:
+                        source.SkipField();
+                        break;
+                }
+            }
+            if(newObjectKey >= 0 && (options & NetObjectOptions.AsReference) == 0)
+            {
+                throw new ProtoException("Object key in input stream, but reference-tracking was not expected");
+            }
+            ProtoReader.EndSubItem(token, source);
+
+            return value;
+#endif
+        }
+        /// <summary>
+        /// Writes an *implementation specific* bundled .NET object, including (as options) type-metadata, identity/re-use, etc.
+        /// </summary>
+        public static void WriteNetObject(object value, ProtoWriter dest, int key, NetObjectOptions options)
+        {
+#if FEAT_IKVM
+            throw new NotSupportedException();
+#else
+            if (dest == null) throw new ArgumentNullException("dest");
+            bool dynamicType = (options & NetObjectOptions.DynamicType) != 0,
+                 asReference = (options & NetObjectOptions.AsReference) != 0;
+            WireType wireType = dest.WireType;
+            SubItemToken token = ProtoWriter.StartSubItem(null, dest);
+            bool writeObject = true;
+            if (asReference)
+            {
+                bool existing;
+                int objectKey = dest.NetCache.AddObjectKey(value, out existing);
+                ProtoWriter.WriteFieldHeader(existing ? FieldExistingObjectKey : FieldNewObjectKey, WireType.Variant, dest);
+                ProtoWriter.WriteInt32(objectKey, dest);
+                if (existing)
+                {
+                    writeObject = false;
+                }
+            }
+
+            if (writeObject)
+            {
+                if (dynamicType)
+                {
+                    bool existing;
+                    Type type = value.GetType();
+
+                    if (!(value is string))
+                    {
+                        key = dest.GetTypeKey(ref type);
+                        if (key < 0) throw new InvalidOperationException("Dynamic type is not a contract-type: " + type.Name);
+                    }
+                    int typeKey = dest.NetCache.AddObjectKey(type, out existing);
+                    ProtoWriter.WriteFieldHeader(existing ? FieldExistingTypeKey : FieldNewTypeKey, WireType.Variant, dest);
+                    ProtoWriter.WriteInt32(typeKey, dest);
+                    if (!existing)
+                    {
+                        ProtoWriter.WriteFieldHeader(FieldTypeName, WireType.String, dest);
+                        ProtoWriter.WriteString(dest.SerializeType(type), dest);
+                    }
+                    
+                }
+                ProtoWriter.WriteFieldHeader(FieldObject, wireType, dest);
+                if (value is string)
+                {
+                    ProtoWriter.WriteString((string)value, dest);
+                }
+                else { 
+                    ProtoWriter.WriteObject(value, key, dest);
+                }
+            }
+            ProtoWriter.EndSubItem(token, dest);
+#endif
+        }
+    }
+}

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/BclHelpers.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 69695e052455cac449470837a9e61a5d
+timeCreated: 1515899113
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 73 - 0
Unity/Assets/Plugins/protobuf-net/BufferExtension.cs

@@ -0,0 +1,73 @@
+using System;
+using System.IO;
+
+namespace ProtoBuf
+{
+    /// <summary>
+    /// Provides a simple buffer-based implementation of an <see cref="IExtension">extension</see> object.
+    /// </summary>
+    public sealed class BufferExtension : IExtension
+    {
+        private byte[] buffer;
+
+        int IExtension.GetLength()
+        {
+            return buffer == null ? 0 : buffer.Length;
+        }
+
+        Stream IExtension.BeginAppend()
+        {
+            return new MemoryStream();
+        }
+
+        void IExtension.EndAppend(Stream stream, bool commit)
+        {
+            using (stream)
+            {
+                int len;
+                if (commit && (len = (int)stream.Length) > 0)
+                {
+                    MemoryStream ms = (MemoryStream)stream;
+
+                    if (buffer == null)
+                    {   // allocate new buffer
+                        buffer = ms.ToArray();
+                    }
+                    else
+                    {   // resize and copy the data
+                        // note: Array.Resize not available on CF
+                        int offset = buffer.Length;
+                        byte[] tmp = new byte[offset + len];
+                        Helpers.BlockCopy(buffer, 0, tmp, 0, offset);
+
+#if PORTABLE || WINRT // no GetBuffer() - fine, we'll use Read instead
+                        int bytesRead;
+                        long oldPos = ms.Position;
+                        ms.Position = 0;
+                        while (len > 0 && (bytesRead = ms.Read(tmp, offset, len)) > 0)
+                        {
+                            len -= bytesRead;
+                            offset += bytesRead;
+                        }
+                        if(len != 0) throw new EndOfStreamException();
+                        ms.Position = oldPos;
+#else
+                        Helpers.BlockCopy(ms.GetBuffer(), 0, tmp, offset, len);
+#endif
+                        buffer = tmp;
+                    }
+                }
+            }
+        }
+
+        Stream IExtension.BeginQuery()
+        {
+            return buffer == null ? Stream.Null : new MemoryStream(buffer);
+        }
+
+        void IExtension.EndQuery(Stream stream)
+        {
+            using (stream) { } // just clean up
+        }
+    }
+}

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/BufferExtension.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 35d4c37b88b78c74b9028da5eca9152b
+timeCreated: 1515899112
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 103 - 0
Unity/Assets/Plugins/protobuf-net/BufferPool.cs

@@ -0,0 +1,103 @@
+
+using System.Threading;
+namespace ProtoBuf
+{
+    internal sealed class BufferPool
+    {
+        internal static void Flush()
+        {
+#if PLAT_NO_INTERLOCKED
+            lock(pool)
+            {
+                for (int i = 0; i < pool.Length; i++) pool[i] = null;
+            }
+#else
+            for (int i = 0; i < pool.Length; i++)
+            {
+                Interlocked.Exchange(ref pool[i], null); // and drop the old value on the floor
+            }
+#endif
+        }
+        private BufferPool() { }
+        const int PoolSize = 20;
+        internal const int BufferLength = 1024;
+        private static readonly object[] pool = new object[PoolSize];
+
+        internal static byte[] GetBuffer()
+        {
+            object tmp;
+            #if PLAT_NO_INTERLOCKED
+            lock(pool)
+            {
+                for (int i = 0; i < pool.Length; i++)
+                {
+                    if((tmp = pool[i]) != null)
+                    {
+                        pool[i] = null;
+                        return (byte[])tmp;
+                    }
+                }
+            }
+#else
+            for (int i = 0; i < pool.Length; i++)
+            {
+                if ((tmp = Interlocked.Exchange(ref pool[i], null)) != null) return (byte[])tmp;
+            }
+#endif
+            return new byte[BufferLength];
+        }
+        internal static void ResizeAndFlushLeft(ref byte[] buffer, int toFitAtLeastBytes, int copyFromIndex, int copyBytes)
+        {
+            Helpers.DebugAssert(buffer != null);
+            Helpers.DebugAssert(toFitAtLeastBytes > buffer.Length);
+            Helpers.DebugAssert(copyFromIndex >= 0);
+            Helpers.DebugAssert(copyBytes >= 0);
+
+            // try doubling, else match
+            int newLength = buffer.Length * 2;
+            if (newLength < toFitAtLeastBytes) newLength = toFitAtLeastBytes;
+
+            byte[] newBuffer = new byte[newLength];
+            if (copyBytes > 0)
+            {
+                Helpers.BlockCopy(buffer, copyFromIndex, newBuffer, 0, copyBytes);
+            }
+            if (buffer.Length == BufferPool.BufferLength)
+            {
+                BufferPool.ReleaseBufferToPool(ref buffer);
+            }
+            buffer = newBuffer;
+        }
+        internal static void ReleaseBufferToPool(ref byte[] buffer)
+        {
+            if (buffer == null) return;
+            if (buffer.Length == BufferLength)
+            {
+#if PLAT_NO_INTERLOCKED
+                lock (pool)
+                {
+                    for (int i = 0; i < pool.Length; i++)
+                    {
+                        if(pool[i] == null)
+                        {
+                            pool[i] = buffer;
+                            break;
+                        }
+                    }
+                }
+#else
+                for (int i = 0; i < pool.Length; i++)
+                {
+                    if (Interlocked.CompareExchange(ref pool[i], buffer, null) == null)
+                    {
+                        break; // found a null; swapped it in
+                    }
+                }
+#endif
+            }
+            // if no space, just drop it on the floor
+            buffer = null;
+        }
+
+    }
+}

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/BufferPool.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 0af08889f498edd47ae2a63d9852bb97
+timeCreated: 1515899112
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 33 - 0
Unity/Assets/Plugins/protobuf-net/CallbackAttributes.cs

@@ -0,0 +1,33 @@
+using System;
+using System.ComponentModel;
+
+namespace ProtoBuf
+{
+    /// <summary>Specifies a method on the root-contract in an hierarchy to be invoked before serialization.</summary>
+    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
+#if !CF && !SILVERLIGHT && !MONODROID && !WINRT && !IOS && !PORTABLE
+    [ImmutableObject(true)]
+#endif
+    public sealed class ProtoBeforeSerializationAttribute : Attribute { }
+
+    /// <summary>Specifies a method on the root-contract in an hierarchy to be invoked after serialization.</summary>
+    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
+#if !CF && !SILVERLIGHT && !MONODROID && !WINRT && !IOS && !PORTABLE
+    [ImmutableObject(true)]
+#endif
+    public sealed class ProtoAfterSerializationAttribute : Attribute { }
+
+    /// <summary>Specifies a method on the root-contract in an hierarchy to be invoked before deserialization.</summary>
+    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
+#if !CF && !SILVERLIGHT && !MONODROID && !WINRT && !IOS && !PORTABLE
+    [ImmutableObject(true)]
+#endif
+    public sealed class ProtoBeforeDeserializationAttribute : Attribute { }
+
+    /// <summary>Specifies a method on the root-contract in an hierarchy to be invoked after deserialization.</summary>
+    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
+#if !CF && !SILVERLIGHT && !MONODROID && !WINRT && !IOS && !PORTABLE
+    [ImmutableObject(true)]
+#endif
+    public sealed class ProtoAfterDeserializationAttribute : Attribute { }
+}

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/CallbackAttributes.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: d9062a6e5fc89b34e83029c618bd923f
+timeCreated: 1515899114
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 3 - 3
Unity/Assets/Plugins/protobuf-net/Compiler.meta

@@ -1,8 +1,8 @@
 fileFormatVersion: 2
-guid: 768a2a45d52da324ca87d347cf472305
+guid: aaa90da5f976d9847b630b506f37fe57
 folderAsset: yes
-timeCreated: 1513686875
-licenseType: Free
+timeCreated: 1515899111
+licenseType: Pro
 DefaultImporter:
   userData: 
   assetBundleName: 

+ 1451 - 0
Unity/Assets/Plugins/protobuf-net/Compiler/CompilerContext.cs

@@ -0,0 +1,1451 @@
+#if FEAT_COMPILER
+//#define DEBUG_COMPILE
+using System;
+using System.Threading;
+using ProtoBuf.Meta;
+using ProtoBuf.Serializers;
+
+#if FEAT_IKVM
+using Type = IKVM.Reflection.Type;
+using IKVM.Reflection;
+using IKVM.Reflection.Emit;
+#else
+using System.Reflection;
+using System.Reflection.Emit;
+#endif
+
+
+namespace ProtoBuf.Compiler
+{
+    internal struct CodeLabel
+    {
+        public readonly Label Value;
+        public readonly int Index;
+        public CodeLabel(Label value, int index)
+        {
+            this.Value = value;
+            this.Index = index;
+        }
+    }
+    internal sealed class CompilerContext
+    {
+        public TypeModel Model { get { return model; } }
+
+#if !(FX11 || FEAT_IKVM)
+        readonly DynamicMethod method;
+        static int next;
+#endif
+
+        internal CodeLabel DefineLabel()
+        {
+            CodeLabel result = new CodeLabel(il.DefineLabel(), nextLabel++);
+            return result;
+        }
+        internal void MarkLabel(CodeLabel label)
+        {
+            il.MarkLabel(label.Value);
+#if DEBUG_COMPILE
+            Helpers.DebugWriteLine("#: " + label.Index);
+#endif
+        }
+
+#if !(FX11 || FEAT_IKVM)
+        public static ProtoSerializer BuildSerializer(IProtoSerializer head, TypeModel model)
+        {
+            Type type = head.ExpectedType;
+            try
+            {
+                CompilerContext ctx = new CompilerContext(type, true, true, model, typeof(object));
+                ctx.LoadValue(ctx.InputValue);
+                ctx.CastFromObject(type);
+                ctx.WriteNullCheckedTail(type, head, null);
+                ctx.Emit(OpCodes.Ret);
+                return (ProtoSerializer)ctx.method.CreateDelegate(
+                    typeof(ProtoSerializer));
+            }
+            catch (Exception ex)
+            {
+                string name = type.FullName;
+                if(string.IsNullOrEmpty(name)) name = type.Name;
+                throw new InvalidOperationException("It was not possible to prepare a serializer for: " + name, ex);
+            }
+        }
+        /*public static ProtoCallback BuildCallback(IProtoTypeSerializer head)
+        {
+            Type type = head.ExpectedType;
+            CompilerContext ctx = new CompilerContext(type, true, true);
+            using (Local typedVal = new Local(ctx, type))
+            {
+                ctx.LoadValue(Local.InputValue);
+                ctx.CastFromObject(type);
+                ctx.StoreValue(typedVal);
+                CodeLabel[] jumpTable = new CodeLabel[4];
+                for(int i = 0 ; i < jumpTable.Length ; i++) {
+                    jumpTable[i] = ctx.DefineLabel();
+                }
+                ctx.LoadReaderWriter();
+                ctx.Switch(jumpTable);
+                ctx.Return();
+                for(int i = 0 ; i < jumpTable.Length ; i++) {
+                    ctx.MarkLabel(jumpTable[i]);
+                    if (head.HasCallbacks((TypeModel.CallbackType)i))
+                    {
+                        head.EmitCallback(ctx, typedVal, (TypeModel.CallbackType)i);
+                    }
+                    ctx.Return();
+                }                
+            }
+            
+            ctx.Emit(OpCodes.Ret);
+            return (ProtoCallback)ctx.method.CreateDelegate(
+                typeof(ProtoCallback));
+        }*/
+        public static ProtoDeserializer BuildDeserializer(IProtoSerializer head, TypeModel model)
+        {
+            Type type = head.ExpectedType;
+            CompilerContext ctx = new CompilerContext(type, false, true, model, typeof(object));
+            
+            using (Local typedVal = new Local(ctx, type))
+            {
+                if (!type.IsValueType)
+                {
+                    ctx.LoadValue(ctx.InputValue);
+                    ctx.CastFromObject(type);
+                    ctx.StoreValue(typedVal);
+                }
+                else
+                {   
+                    ctx.LoadValue(ctx.InputValue);
+                    CodeLabel notNull = ctx.DefineLabel(), endNull = ctx.DefineLabel();
+                    ctx.BranchIfTrue(notNull, true);
+
+                    ctx.LoadAddress(typedVal, type);
+                    ctx.EmitCtor(type);
+                    ctx.Branch(endNull, true);
+
+                    ctx.MarkLabel(notNull);
+                    ctx.LoadValue(ctx.InputValue);
+                    ctx.CastFromObject(type);
+                    ctx.StoreValue(typedVal);
+
+                    ctx.MarkLabel(endNull);
+                }
+                head.EmitRead(ctx, typedVal);
+
+                if (head.ReturnsValue) {
+                    ctx.StoreValue(typedVal);
+                }
+
+                ctx.LoadValue(typedVal);
+                ctx.CastToObject(type);
+            }
+            ctx.Emit(OpCodes.Ret);
+            return (ProtoDeserializer)ctx.method.CreateDelegate(
+                typeof(ProtoDeserializer));
+        }
+#endif
+        internal void Return()
+        {
+            Emit(OpCodes.Ret);
+        }
+
+        static bool IsObject(Type type)
+        {
+#if FEAT_IKVM
+            return type.FullName == "System.Object";
+#else
+            return type == typeof(object);
+#endif
+        }
+        internal void CastToObject(Type type)
+        {
+            if(IsObject(type))
+            { }
+            else if (type.IsValueType)
+            {
+                il.Emit(OpCodes.Box, type);
+#if DEBUG_COMPILE
+                Helpers.DebugWriteLine(OpCodes.Box + ": " + type);
+#endif
+            }
+            else
+            {
+                il.Emit(OpCodes.Castclass, MapType(typeof(object)));
+#if DEBUG_COMPILE
+                Helpers.DebugWriteLine(OpCodes.Castclass + ": " + type);
+#endif
+            }
+        }
+
+        internal void CastFromObject(Type type)
+        {
+            if (IsObject(type))
+            { }
+            else if (type.IsValueType)
+            {
+                switch (MetadataVersion)
+                {
+                    case ILVersion.Net1:
+                        il.Emit(OpCodes.Unbox, type);
+                        il.Emit(OpCodes.Ldobj, type);
+#if DEBUG_COMPILE
+                        Helpers.DebugWriteLine(OpCodes.Unbox + ": " + type);
+                        Helpers.DebugWriteLine(OpCodes.Ldobj + ": " + type);
+#endif
+                        break;
+                    default:
+#if FX11
+                        throw new NotSupportedException();
+#else
+                        il.Emit(OpCodes.Unbox_Any, type);
+#if DEBUG_COMPILE
+                        Helpers.DebugWriteLine(OpCodes.Unbox_Any + ": " + type);
+#endif
+                        break;
+#endif
+                }
+            }
+            else
+            {
+                il.Emit(OpCodes.Castclass, type);
+#if DEBUG_COMPILE
+                Helpers.DebugWriteLine(OpCodes.Castclass + ": " + type);
+#endif
+            }
+        }
+        private readonly bool isStatic;
+#if !SILVERLIGHT
+        private readonly RuntimeTypeModel.SerializerPair[] methodPairs;
+
+        internal MethodBuilder GetDedicatedMethod(int metaKey, bool read)
+        {
+            if (methodPairs == null) return null;
+            // but if we *do* have pairs, we demand that we find a match...
+            for (int i = 0; i < methodPairs.Length; i++ )
+            {
+                if (methodPairs[i].MetaKey == metaKey) { return read ? methodPairs[i].Deserialize : methodPairs[i].Serialize; }
+            }
+            throw new ArgumentException("Meta-key not found", "metaKey");
+        }
+
+        internal int MapMetaKeyToCompiledKey(int metaKey)
+        {
+            if (metaKey < 0 || methodPairs == null) return metaKey; // all meta, or a dummy/wildcard key
+
+            for (int i = 0; i < methodPairs.Length; i++)
+            {
+                if (methodPairs[i].MetaKey == metaKey) return i;
+            }
+            throw new ArgumentException("Key could not be mapped: " + metaKey.ToString(), "metaKey");
+        }
+#else
+        internal int MapMetaKeyToCompiledKey(int metaKey)
+        {
+            return metaKey;
+        }
+#endif
+
+        private readonly bool isWriter;
+#if FX11 || FEAT_IKVM
+        internal bool NonPublic { get { return false; } }
+#else
+        private readonly bool nonPublic;
+        internal bool NonPublic { get { return nonPublic; } }
+#endif
+
+
+        private readonly Local inputValue;
+        public Local InputValue { get { return inputValue; } }
+#if !(SILVERLIGHT || PHONE8)
+        private readonly string assemblyName;
+        internal CompilerContext(ILGenerator il, bool isStatic, bool isWriter, RuntimeTypeModel.SerializerPair[] methodPairs, TypeModel model, ILVersion metadataVersion, string assemblyName, Type inputType)
+        {
+            if (il == null) throw new ArgumentNullException("il");
+            if (methodPairs == null) throw new ArgumentNullException("methodPairs");
+            if (model == null) throw new ArgumentNullException("model");
+            if (Helpers.IsNullOrEmpty(assemblyName)) throw new ArgumentNullException("assemblyName");
+            this.assemblyName = assemblyName;
+            this.isStatic = isStatic;
+            this.methodPairs = methodPairs;
+            this.il = il;
+            // nonPublic = false; <== implicit
+            this.isWriter = isWriter;
+            this.model = model;
+            this.metadataVersion = metadataVersion;
+            if (inputType != null) this.inputValue = new Local(null, inputType);
+        }
+#endif
+#if !(FX11 || FEAT_IKVM)
+        private CompilerContext(Type associatedType, bool isWriter, bool isStatic, TypeModel model, Type inputType)
+        {
+            if (model == null) throw new ArgumentNullException("model");
+#if FX11
+            metadataVersion = ILVersion.Net1;
+#else
+            metadataVersion = ILVersion.Net2;
+#endif
+            this.isStatic = isStatic;
+            this.isWriter = isWriter;
+            this.model = model;
+            nonPublic = true;
+            Type[] paramTypes;
+            Type returnType;
+            if (isWriter)
+            {
+                returnType = typeof(void);
+                paramTypes = new Type[] { typeof(object), typeof(ProtoWriter) };
+            }
+            else
+            {
+                returnType = typeof(object);
+                paramTypes = new Type[] { typeof(object), typeof(ProtoReader) };
+            }
+            int uniqueIdentifier;
+#if PLAT_NO_INTERLOCKED
+            uniqueIdentifier = ++next;
+#else
+            uniqueIdentifier = Interlocked.Increment(ref next);
+#endif
+            method = new DynamicMethod("proto_" + uniqueIdentifier.ToString(), returnType, paramTypes, associatedType.IsInterface ? typeof(object) : associatedType, true);
+            this.il = method.GetILGenerator();
+            if (inputType != null) this.inputValue = new Local(null, inputType);
+        }
+
+#endif
+        private readonly ILGenerator il;
+
+        private void Emit(OpCode opcode)
+        {
+            il.Emit(opcode);
+#if DEBUG_COMPILE
+            Helpers.DebugWriteLine(opcode.ToString());
+#endif
+        }
+        public void LoadValue(string value)
+        {
+            if (value == null)
+            {
+                LoadNullRef();
+            }
+            else
+            {
+                il.Emit(OpCodes.Ldstr, value);
+#if DEBUG_COMPILE
+                Helpers.DebugWriteLine(OpCodes.Ldstr + ": " + value);
+#endif
+            }
+        }
+        public void LoadValue(float value)
+        {
+            il.Emit(OpCodes.Ldc_R4, value);
+#if DEBUG_COMPILE
+            Helpers.DebugWriteLine(OpCodes.Ldc_R4 + ": " + value);
+#endif
+        }
+        public void LoadValue(double value)
+        {
+            il.Emit(OpCodes.Ldc_R8, value);
+#if DEBUG_COMPILE
+            Helpers.DebugWriteLine(OpCodes.Ldc_R8 + ": " + value);
+#endif
+        }
+        public void LoadValue(long value)
+        {
+            il.Emit(OpCodes.Ldc_I8, value);
+#if DEBUG_COMPILE
+            Helpers.DebugWriteLine(OpCodes.Ldc_I8 + ": " + value);
+#endif
+        }
+        public void LoadValue(int value)
+        {
+            switch (value)
+            {
+                case 0: Emit(OpCodes.Ldc_I4_0); break;
+                case 1: Emit(OpCodes.Ldc_I4_1); break;
+                case 2: Emit(OpCodes.Ldc_I4_2); break;
+                case 3: Emit(OpCodes.Ldc_I4_3); break;
+                case 4: Emit(OpCodes.Ldc_I4_4); break;
+                case 5: Emit(OpCodes.Ldc_I4_5); break;
+                case 6: Emit(OpCodes.Ldc_I4_6); break;
+                case 7: Emit(OpCodes.Ldc_I4_7); break;
+                case 8: Emit(OpCodes.Ldc_I4_8); break;
+                case -1: Emit(OpCodes.Ldc_I4_M1); break;
+                default:
+                    if (value >= -128 && value <= 127)
+                    {
+                        il.Emit(OpCodes.Ldc_I4_S, (sbyte)value);
+#if DEBUG_COMPILE
+                        Helpers.DebugWriteLine(OpCodes.Ldc_I4_S + ": " + value);
+#endif
+                    }
+                    else
+                    {
+                        il.Emit(OpCodes.Ldc_I4, value);
+#if DEBUG_COMPILE
+                        Helpers.DebugWriteLine(OpCodes.Ldc_I4 + ": " + value);
+#endif
+                    }
+                    break;
+
+            }
+        }
+
+        MutableList locals = new MutableList();
+        internal LocalBuilder GetFromPool(Type type)
+        {
+            int count = locals.Count;
+            for (int i = 0; i < count; i++)
+            {
+                LocalBuilder item = (LocalBuilder)locals[i];
+                if (item != null && item.LocalType == type)
+                {
+                    locals[i] = null; // remove from pool
+                    return item;
+                }
+            }
+            LocalBuilder result = il.DeclareLocal(type);
+#if DEBUG_COMPILE
+            Helpers.DebugWriteLine("$ " + result + ": " + type);
+#endif
+            return result;
+        }
+        //
+        internal void ReleaseToPool(LocalBuilder value)
+        {
+            int count = locals.Count;
+            for (int i = 0; i < count; i++)
+            {
+                if (locals[i] == null)
+                {
+                    locals[i] = value; // released into existing slot
+                    return;
+                }
+            }
+            locals.Add(value); // create a new slot
+        }
+        public void LoadReaderWriter()
+        {
+            Emit(isStatic ? OpCodes.Ldarg_1 : OpCodes.Ldarg_2);
+        }
+        public void StoreValue(Local local)
+        {
+            if (local == this.InputValue)
+            {
+                byte b = isStatic ? (byte) 0 : (byte)1;
+                il.Emit(OpCodes.Starg_S, b);
+#if DEBUG_COMPILE
+                Helpers.DebugWriteLine(OpCodes.Starg_S + ": $" + b);
+#endif                
+            }
+            else
+            {
+#if !FX11
+                switch (local.Value.LocalIndex)
+                {
+                    case 0: Emit(OpCodes.Stloc_0); break;
+                    case 1: Emit(OpCodes.Stloc_1); break;
+                    case 2: Emit(OpCodes.Stloc_2); break;
+                    case 3: Emit(OpCodes.Stloc_3); break;
+                    default:
+#endif
+                        OpCode code = UseShortForm(local) ? OpCodes.Stloc_S : OpCodes.Stloc;
+                        il.Emit(code, local.Value);
+#if DEBUG_COMPILE
+                        Helpers.DebugWriteLine(code + ": $" + local.Value);
+#endif
+#if !FX11
+                        break;
+                }
+#endif
+            }
+        }
+        public void LoadValue(Local local)
+        {
+            if (local == null) { /* nothing to do; top of stack */}
+            else if (local == this.InputValue)
+            {
+                Emit(isStatic ? OpCodes.Ldarg_0 : OpCodes.Ldarg_1);
+            }
+            else
+            {
+#if !FX11
+                switch (local.Value.LocalIndex)
+                {
+                    case 0: Emit(OpCodes.Ldloc_0); break;
+                    case 1: Emit(OpCodes.Ldloc_1); break;
+                    case 2: Emit(OpCodes.Ldloc_2); break;
+                    case 3: Emit(OpCodes.Ldloc_3); break;
+                    default:
+#endif             
+                        OpCode code = UseShortForm(local) ? OpCodes.Ldloc_S :  OpCodes.Ldloc;
+                        il.Emit(code, local.Value);
+#if DEBUG_COMPILE
+                        Helpers.DebugWriteLine(code + ": $" + local.Value);
+#endif
+#if !FX11
+                        break;
+                }
+#endif
+            }
+        }
+        public Local GetLocalWithValue(Type type, Compiler.Local fromValue)
+        {
+            if (fromValue != null)
+            {
+                if (fromValue.Type == type) return fromValue.AsCopy();
+                // otherwise, load onto the stack and let the default handling (below) deal with it
+                LoadValue(fromValue);
+                if (!type.IsValueType && (fromValue.Type == null || !type.IsAssignableFrom(fromValue.Type)))
+                { // need to cast
+                    Cast(type);
+                }
+            }
+            // need to store the value from the stack
+            Local result = new Local(this, type);
+            StoreValue(result);
+            return result;
+        }
+        internal void EmitBasicRead(string methodName, Type expectedType)
+        {
+            MethodInfo method = MapType(typeof(ProtoReader)).GetMethod(
+                methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
+            if (method == null || method.ReturnType != expectedType
+                || method.GetParameters().Length != 0) throw new ArgumentException("methodName");
+            LoadReaderWriter();
+            EmitCall(method);            
+        }
+        internal void EmitBasicRead(Type helperType, string methodName, Type expectedType)
+        {
+            MethodInfo method = helperType.GetMethod(
+                methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
+            if (method == null || method.ReturnType != expectedType
+                || method.GetParameters().Length != 1) throw new ArgumentException("methodName");
+            LoadReaderWriter();
+            EmitCall(method);
+        }
+        internal void EmitBasicWrite(string methodName, Compiler.Local fromValue)
+        {
+            if (Helpers.IsNullOrEmpty(methodName)) throw new ArgumentNullException("methodName");
+            LoadValue(fromValue);
+            LoadReaderWriter();
+            EmitCall(GetWriterMethod(methodName));
+        }
+        private MethodInfo GetWriterMethod(string methodName)
+        {
+            Type writerType = MapType(typeof(ProtoWriter));
+            MethodInfo[] methods = writerType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
+            foreach (MethodInfo method in methods)
+            {
+                if(method.Name != methodName) continue;
+                ParameterInfo[] pis = method.GetParameters();
+                if (pis.Length == 2 && pis[1].ParameterType == writerType) return method;
+            }
+            throw new ArgumentException("No suitable method found for: " + methodName, "methodName");
+        }
+        internal void EmitWrite(Type helperType, string methodName, Compiler.Local valueFrom)
+        {
+            if (Helpers.IsNullOrEmpty(methodName)) throw new ArgumentNullException("methodName");
+            MethodInfo method = helperType.GetMethod(
+                methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
+            if (method == null || method.ReturnType != MapType(typeof(void))) throw new ArgumentException("methodName");
+            LoadValue(valueFrom);
+            LoadReaderWriter();
+            EmitCall(method);
+        }
+        public void EmitCall(MethodInfo method)
+        {
+            Helpers.DebugAssert(method != null);
+            CheckAccessibility(method);
+            OpCode opcode = (method.IsStatic || method.DeclaringType.IsValueType) ? OpCodes.Call : OpCodes.Callvirt;
+            il.EmitCall(opcode, method, null);
+#if DEBUG_COMPILE
+            Helpers.DebugWriteLine(opcode + ": " + method + " on " + method.DeclaringType);
+#endif
+        }
+        /// <summary>
+        /// Pushes a null reference onto the stack. Note that this should only
+        /// be used to return a null (or set a variable to null); for null-tests
+        /// use BranchIfTrue / BranchIfFalse.
+        /// </summary>
+        public void LoadNullRef()
+        {
+            Emit(OpCodes.Ldnull);
+        }
+
+        private int nextLabel;
+
+        internal void WriteNullCheckedTail(Type type, IProtoSerializer tail, Compiler.Local valueFrom)
+        {
+            if (type.IsValueType)
+            {
+                Type underlyingType = null;
+#if !FX11
+                underlyingType = Helpers.GetUnderlyingType(type);
+#endif
+                if (underlyingType == null)
+                { // not a nullable T; can invoke directly
+                    tail.EmitWrite(this, valueFrom);
+                }
+                else
+                { // nullable T; check HasValue
+                    using (Compiler.Local valOrNull = GetLocalWithValue(type, valueFrom))
+                    {
+                        LoadAddress(valOrNull, type);
+                        LoadValue(type.GetProperty("HasValue"));
+                        CodeLabel @end = DefineLabel();
+                        BranchIfFalse(@end, false);
+                        LoadAddress(valOrNull, type);
+                        EmitCall(type.GetMethod("GetValueOrDefault", Helpers.EmptyTypes));
+                        tail.EmitWrite(this, null);
+                        MarkLabel(@end);
+                    }
+                }
+            }
+            else
+            { // ref-type; do a null-check
+                LoadValue(valueFrom);
+                CopyValue();
+                CodeLabel hasVal = DefineLabel(), @end = DefineLabel();
+                BranchIfTrue(hasVal, true);
+                DiscardValue();
+                Branch(@end, false);
+                MarkLabel(hasVal);
+                tail.EmitWrite(this, null);
+                MarkLabel(@end);
+            }
+        }
+
+        internal void ReadNullCheckedTail(Type type, IProtoSerializer tail, Compiler.Local valueFrom)
+        {
+#if !FX11
+            Type underlyingType;
+            
+            if (type.IsValueType && (underlyingType = Helpers.GetUnderlyingType(type)) != null)
+            {
+                if(tail.RequiresOldValue)
+                {
+                    // we expect the input value to be in valueFrom; need to unpack it from T?
+                    using (Local loc = GetLocalWithValue(type, valueFrom))
+                    {
+                        LoadAddress(loc, type);
+                        EmitCall(type.GetMethod("GetValueOrDefault", Helpers.EmptyTypes));
+                    }
+                }
+                else
+                {
+                    Helpers.DebugAssert(valueFrom == null); // not expecting a valueFrom in this case
+                }
+                tail.EmitRead(this, null); // either unwrapped on the stack or not provided
+                if (tail.ReturnsValue)
+                {
+                    // now re-wrap the value
+                    EmitCtor(type, underlyingType);
+                }
+                return;
+            }
+#endif
+            // either a ref-type of a non-nullable struct; treat "as is", even if null
+            // (the type-serializer will handle the null case; it needs to allow null
+            // inputs to perform the correct type of subclass creation)
+            tail.EmitRead(this, valueFrom);
+        }
+
+        public void EmitCtor(Type type)
+        {
+            EmitCtor(type, Helpers.EmptyTypes);
+        }
+
+        public void EmitCtor(ConstructorInfo ctor)
+        {
+            if (ctor == null) throw new ArgumentNullException("ctor");
+            CheckAccessibility(ctor);
+            il.Emit(OpCodes.Newobj, ctor);
+#if DEBUG_COMPILE
+            Helpers.DebugWriteLine(OpCodes.Newobj + ": " + ctor.DeclaringType);
+#endif
+        }
+
+        public void EmitCtor(Type type, params Type[] parameterTypes)
+        {
+            Helpers.DebugAssert(type != null);
+            Helpers.DebugAssert(parameterTypes != null);
+            if (type.IsValueType && parameterTypes.Length == 0)
+            {
+                il.Emit(OpCodes.Initobj, type);
+#if DEBUG_COMPILE
+                Helpers.DebugWriteLine(OpCodes.Initobj + ": " + type);
+#endif
+            }
+            else
+            {
+                ConstructorInfo ctor =  Helpers.GetConstructor(type, parameterTypes, true);
+                if (ctor == null) throw new InvalidOperationException("No suitable constructor found for " + type.FullName);
+                EmitCtor(ctor);
+            }
+        }
+#if !(PHONE8 || SILVERLIGHT || FX11)
+        BasicList knownTrustedAssemblies, knownUntrustedAssemblies;
+#endif
+        bool InternalsVisible(Assembly assembly)
+        {
+#if PHONE8 || SILVERLIGHT || FX11
+            return false;
+#else
+            if (Helpers.IsNullOrEmpty(assemblyName)) return false;
+            if (knownTrustedAssemblies != null)
+            {
+                if (knownTrustedAssemblies.IndexOfReference(assembly) >= 0)
+                {
+                    return true;
+                }
+            }
+            if (knownUntrustedAssemblies != null)
+            {
+                if (knownUntrustedAssemblies.IndexOfReference(assembly) >= 0)
+                {
+                    return false;
+                }
+            }
+            bool isTrusted = false;
+            Type attributeType = MapType(typeof(System.Runtime.CompilerServices.InternalsVisibleToAttribute));
+            if(attributeType == null) return false;
+#if FEAT_IKVM
+            foreach (CustomAttributeData attrib in assembly.__GetCustomAttributes(attributeType, false))
+            {
+                if (attrib.ConstructorArguments.Count == 1)
+                {
+                    string privelegedAssembly = attrib.ConstructorArguments[0].Value as string;
+                    if (privelegedAssembly == assemblyName || privelegedAssembly.StartsWith(assemblyName + ","))
+                    {
+                        isTrusted = true;
+                        break;
+                    }
+                }
+            }
+#else
+            foreach (System.Runtime.CompilerServices.InternalsVisibleToAttribute attrib in assembly.GetCustomAttributes(attributeType, false))
+            {
+                if (attrib.AssemblyName == assemblyName || attrib.AssemblyName.StartsWith(assemblyName + ","))
+                {
+                    isTrusted = true;
+                    break;
+                }
+            }
+#endif
+            if (isTrusted)
+            {
+                if (knownTrustedAssemblies == null) knownTrustedAssemblies = new BasicList();
+                knownTrustedAssemblies.Add(assembly);
+            }
+            else
+            {
+                if (knownUntrustedAssemblies == null) knownUntrustedAssemblies = new BasicList();
+                knownUntrustedAssemblies.Add(assembly);
+            }
+            return isTrusted;
+#endif
+        }
+        internal void CheckAccessibility(MemberInfo member)
+        {
+            if (member == null)
+            {
+                throw new ArgumentNullException("member");
+            }
+
+            MemberTypes memberType = member.MemberType;
+            Type type;
+            if (!NonPublic)
+            {
+                bool isPublic;
+                switch (memberType)
+                {
+                    case MemberTypes.TypeInfo:
+                        // top-level type
+                        type = (Type)member;
+                        isPublic = type.IsPublic || InternalsVisible(type.Assembly);
+                        break;
+                    case MemberTypes.NestedType:
+                        type = (Type)member;
+                        do
+                        {
+                            isPublic = type.IsNestedPublic || type.IsPublic || ((type.DeclaringType == null || type.IsNestedAssembly || type.IsNestedFamORAssem) && InternalsVisible(type.Assembly));
+                        } while (isPublic && (type = type.DeclaringType) != null); // ^^^ !type.IsNested, but not all runtimes have that
+                        break;
+                    case MemberTypes.Field:
+                        FieldInfo field = ((FieldInfo)member);
+                        isPublic = field.IsPublic || ((field.IsAssembly || field.IsFamilyOrAssembly) && InternalsVisible(field.DeclaringType.Assembly));
+                        break;
+                    case MemberTypes.Constructor:
+                        ConstructorInfo ctor = ((ConstructorInfo)member);
+                        isPublic = ctor.IsPublic || ((ctor.IsAssembly || ctor.IsFamilyOrAssembly) && InternalsVisible(ctor.DeclaringType.Assembly));
+                        break;
+                    case MemberTypes.Method:
+                        MethodInfo method = ((MethodInfo)member);
+                        isPublic = method.IsPublic || ((method.IsAssembly || method.IsFamilyOrAssembly) && InternalsVisible(method.DeclaringType.Assembly));
+                        if (!isPublic)
+                        {
+                            // allow calls to TypeModel protected methods, and methods we are in the process of creating
+                            if(
+#if !SILVERLIGHT
+                                member is MethodBuilder ||
+#endif                
+                                member.DeclaringType == MapType(typeof(TypeModel))) isPublic = true; 
+                        }
+                        break;
+                    case MemberTypes.Property:
+                        isPublic = true; // defer to get/set
+                        break;
+                    default:
+                        throw new NotSupportedException(memberType.ToString());
+                }
+                if (!isPublic)
+                {
+                    switch (memberType)
+                    {
+                        case MemberTypes.TypeInfo:
+                        case MemberTypes.NestedType:
+                            throw new InvalidOperationException("Non-public type cannot be used with full dll compilation: " +
+                                ((Type)member).FullName);
+                        default:
+                            throw new InvalidOperationException("Non-public member cannot be used with full dll compilation: " +
+                                member.DeclaringType.FullName + "." + member.Name);
+                    }
+                    
+                }
+            }
+        }
+
+        public void LoadValue(FieldInfo field)
+        {
+            CheckAccessibility(field);
+            OpCode code = field.IsStatic ? OpCodes.Ldsfld : OpCodes.Ldfld;
+            il.Emit(code, field);
+#if DEBUG_COMPILE
+            Helpers.DebugWriteLine(code + ": " + field + " on " + field.DeclaringType);
+#endif
+        }
+#if FEAT_IKVM
+        public void StoreValue(System.Reflection.FieldInfo field)
+        {
+            StoreValue(MapType(field.DeclaringType).GetField(field.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance));
+        }
+        public void StoreValue(System.Reflection.PropertyInfo property)
+        {
+            StoreValue(MapType(property.DeclaringType).GetProperty(property.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance));
+        }
+        public void LoadValue(System.Reflection.FieldInfo field)
+        {
+            LoadValue(MapType(field.DeclaringType).GetField(field.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance));
+        }
+        public void LoadValue(System.Reflection.PropertyInfo property)
+        {
+            LoadValue(MapType(property.DeclaringType).GetProperty(property.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance));
+        }
+#endif
+        public void StoreValue(FieldInfo field)
+        {
+            CheckAccessibility(field);
+            OpCode code = field.IsStatic ? OpCodes.Stsfld : OpCodes.Stfld;
+            il.Emit(code, field);
+#if DEBUG_COMPILE
+            Helpers.DebugWriteLine(code + ": " + field + " on " + field.DeclaringType);
+#endif
+        }
+        public void LoadValue(PropertyInfo property)
+        {
+            CheckAccessibility(property);
+            EmitCall(Helpers.GetGetMethod(property, true, true));
+        }
+        public void StoreValue(PropertyInfo property)
+        {
+            CheckAccessibility(property);
+            EmitCall(Helpers.GetSetMethod(property, true, true));
+        }
+
+        //internal void EmitInstance()
+        //{
+        //    if (isStatic) throw new InvalidOperationException();
+        //    Emit(OpCodes.Ldarg_0);
+        //}
+
+        internal static void LoadValue(ILGenerator il, int value)
+        {
+            switch (value)
+            {
+                case 0: il.Emit(OpCodes.Ldc_I4_0); break;
+                case 1: il.Emit(OpCodes.Ldc_I4_1); break;
+                case 2: il.Emit(OpCodes.Ldc_I4_2); break;
+                case 3: il.Emit(OpCodes.Ldc_I4_3); break;
+                case 4: il.Emit(OpCodes.Ldc_I4_4); break;
+                case 5: il.Emit(OpCodes.Ldc_I4_5); break;
+                case 6: il.Emit(OpCodes.Ldc_I4_6); break;
+                case 7: il.Emit(OpCodes.Ldc_I4_7); break;
+                case 8: il.Emit(OpCodes.Ldc_I4_8); break;
+                case -1: il.Emit(OpCodes.Ldc_I4_M1); break;
+                default: il.Emit(OpCodes.Ldc_I4, value); break;
+            }
+        }
+
+        private bool UseShortForm(Local local)
+        {
+#if FX11
+            return locals.Count < 256;
+#else
+            return local.Value.LocalIndex < 256;
+#endif
+        }
+#if FEAT_IKVM
+        internal void LoadAddress(Local local, System.Type type)
+        {
+            LoadAddress(local, MapType(type));
+        }
+#endif
+        internal void LoadAddress(Local local, Type type)
+        {
+            if (type.IsValueType)
+            {
+                if (local == null)
+                {
+                    throw new InvalidOperationException("Cannot load the address of a struct at the head of the stack");
+                }
+
+                if (local == this.InputValue)
+                {
+                    il.Emit(OpCodes.Ldarga_S, (isStatic ? (byte)0 : (byte)1));
+#if DEBUG_COMPILE
+                    Helpers.DebugWriteLine(OpCodes.Ldarga_S + ": $" + (isStatic ? 0 : 1));
+#endif
+                }
+                else
+                {
+                    OpCode code = UseShortForm(local) ? OpCodes.Ldloca_S : OpCodes.Ldloca;
+                    il.Emit(code, local.Value);
+#if DEBUG_COMPILE
+                    Helpers.DebugWriteLine(code + ": $" + local.Value);
+#endif
+                }
+
+            }
+            else
+            {   // reference-type; already *is* the address; just load it
+                LoadValue(local);
+            }
+        }
+        internal void Branch(CodeLabel label, bool @short)
+        {
+            OpCode code = @short ? OpCodes.Br_S : OpCodes.Br;
+            il.Emit(code, label.Value);
+#if DEBUG_COMPILE
+            Helpers.DebugWriteLine(code + ": " + label.Index);
+#endif
+        }
+        internal void BranchIfFalse(CodeLabel label, bool @short)
+        {
+            OpCode code = @short ? OpCodes.Brfalse_S :  OpCodes.Brfalse;
+            il.Emit(code, label.Value);
+#if DEBUG_COMPILE
+            Helpers.DebugWriteLine(code + ": " + label.Index);
+#endif
+        }
+
+
+        internal void BranchIfTrue(CodeLabel label, bool @short)
+        {
+            OpCode code = @short ? OpCodes.Brtrue_S : OpCodes.Brtrue;
+            il.Emit(code, label.Value);
+#if DEBUG_COMPILE
+            Helpers.DebugWriteLine(code + ": " + label.Index);
+#endif
+        }
+        internal void BranchIfEqual(CodeLabel label, bool @short)
+        {
+            OpCode code = @short ? OpCodes.Beq_S : OpCodes.Beq;
+            il.Emit(code, label.Value);
+#if DEBUG_COMPILE
+            Helpers.DebugWriteLine(code + ": " + label.Index);
+#endif
+        }
+        //internal void TestEqual()
+        //{
+        //    Emit(OpCodes.Ceq);
+        //}
+
+
+        internal void CopyValue()
+        {
+            Emit(OpCodes.Dup);
+        }
+
+        internal void BranchIfGreater(CodeLabel label, bool @short)
+        {
+            OpCode code = @short ? OpCodes.Bgt_S : OpCodes.Bgt;
+            il.Emit(code, label.Value);
+#if DEBUG_COMPILE
+            Helpers.DebugWriteLine(code + ": " + label.Index);
+#endif
+        }
+
+        internal void BranchIfLess(CodeLabel label, bool @short)
+        {
+            OpCode code = @short ? OpCodes.Blt_S : OpCodes.Blt;
+            il.Emit(code, label.Value);
+#if DEBUG_COMPILE
+            Helpers.DebugWriteLine(code + ": " + label.Index);
+#endif
+        }
+
+        internal void DiscardValue()
+        {
+            Emit(OpCodes.Pop);
+        }
+
+        public void Subtract()
+        {
+            Emit(OpCodes.Sub);
+        }
+
+
+
+        public void Switch(CodeLabel[] jumpTable)
+        {
+            const int MAX_JUMPS = 128;
+
+            if (jumpTable.Length <= MAX_JUMPS)
+            {
+                // simple case
+                Label[] labels = new Label[jumpTable.Length];
+                for (int i = 0; i < labels.Length; i++)
+                {
+                    labels[i] = jumpTable[i].Value;
+                }
+#if DEBUG_COMPILE
+                Helpers.DebugWriteLine(OpCodes.Switch.ToString());
+#endif
+                il.Emit(OpCodes.Switch, labels);
+            }
+            else
+            {
+                // too many to jump easily (especially on Android) - need to split up (note: uses a local pulled from the stack)
+                using (Local val = GetLocalWithValue(MapType(typeof(int)), null))
+                {
+                    int count = jumpTable.Length, offset = 0;
+                    int blockCount = count / MAX_JUMPS;
+                    if ((count % MAX_JUMPS) != 0) blockCount++;
+
+                    Label[] blockLabels = new Label[blockCount];
+                    for (int i = 0; i < blockCount; i++)
+                    {
+                        blockLabels[i] = il.DefineLabel();
+                    }
+                    CodeLabel endOfSwitch = DefineLabel();
+                    
+                    LoadValue(val);
+                    LoadValue(MAX_JUMPS);
+                    Emit(OpCodes.Div);
+#if DEBUG_COMPILE
+                Helpers.DebugWriteLine(OpCodes.Switch.ToString());
+#endif
+                    il.Emit(OpCodes.Switch, blockLabels);
+                    Branch(endOfSwitch, false);
+
+                    Label[] innerLabels = new Label[MAX_JUMPS];
+                    for (int blockIndex = 0; blockIndex < blockCount; blockIndex++)
+                    {
+                        il.MarkLabel(blockLabels[blockIndex]);
+
+                        int itemsThisBlock = Math.Min(MAX_JUMPS, count);
+                        count -= itemsThisBlock;
+                        if (innerLabels.Length != itemsThisBlock) innerLabels = new Label[itemsThisBlock];
+
+                        int subtract = offset;
+                        for (int j = 0; j < itemsThisBlock; j++)
+                        {
+                            innerLabels[j] = jumpTable[offset++].Value;
+                        }
+                        LoadValue(val);
+                        if (subtract != 0) // switches are always zero-based
+                        {
+                            LoadValue(subtract);
+                            Emit(OpCodes.Sub);
+                        }
+#if DEBUG_COMPILE
+                        Helpers.DebugWriteLine(OpCodes.Switch.ToString());
+#endif
+                        il.Emit(OpCodes.Switch, innerLabels);
+                        if (count != 0)
+                        { // force default to the very bottom
+                            Branch(endOfSwitch, false);
+                        }
+                    }
+                    Helpers.DebugAssert(count == 0, "Should use exactly all switch items");
+                    MarkLabel(endOfSwitch);
+                }
+            }
+        }
+
+        internal void EndFinally()
+        {
+            il.EndExceptionBlock();
+#if DEBUG_COMPILE
+            Helpers.DebugWriteLine("EndExceptionBlock");
+#endif
+        }
+
+        internal void BeginFinally()
+        {
+            il.BeginFinallyBlock();
+#if DEBUG_COMPILE
+            Helpers.DebugWriteLine("BeginFinallyBlock");
+#endif
+        }
+
+        internal void EndTry(CodeLabel label, bool @short)
+        {
+            OpCode code = @short ? OpCodes.Leave_S : OpCodes.Leave;
+            il.Emit(code, label.Value);
+#if DEBUG_COMPILE
+            Helpers.DebugWriteLine(code + ": " + label.Index);
+#endif
+        }
+
+        internal CodeLabel BeginTry()
+        {
+            CodeLabel label = new CodeLabel(il.BeginExceptionBlock(), nextLabel++);
+#if DEBUG_COMPILE
+            Helpers.DebugWriteLine("BeginExceptionBlock: " + label.Index);
+#endif
+            return label;
+        }
+#if !FX11
+        internal void Constrain(Type type)
+        {
+            il.Emit(OpCodes.Constrained, type);
+#if DEBUG_COMPILE
+            Helpers.DebugWriteLine(OpCodes.Constrained + ": " + type);
+#endif
+        }
+#endif
+
+        internal void TryCast(Type type)
+        {
+            il.Emit(OpCodes.Isinst, type);
+#if DEBUG_COMPILE
+            Helpers.DebugWriteLine(OpCodes.Isinst + ": " + type);
+#endif
+        }
+
+        internal void Cast(Type type)
+        {
+            il.Emit(OpCodes.Castclass, type);
+#if DEBUG_COMPILE
+            Helpers.DebugWriteLine(OpCodes.Castclass + ": " + type);
+#endif
+        }
+        public IDisposable Using(Local local)
+        {
+            return new UsingBlock(this, local);
+        }
+        private sealed class UsingBlock : IDisposable{
+            private Local local;
+            CompilerContext ctx;
+            CodeLabel label;
+            /// <summary>
+            /// Creates a new "using" block (equivalent) around a variable;
+            /// the variable must exist, and note that (unlike in C#) it is
+            /// the variables *final* value that gets disposed. If you need
+            /// *original* disposal, copy your variable first.
+            /// 
+            /// It is the callers responsibility to ensure that the variable's
+            /// scope fully-encapsulates the "using"; if not, the variable
+            /// may be re-used (and thus re-assigned) unexpectedly.
+            /// </summary>
+            public UsingBlock(CompilerContext ctx, Local local)
+            {
+                if (ctx == null) throw new ArgumentNullException("ctx");
+                if (local == null) throw new ArgumentNullException("local");
+
+                Type type = local.Type;
+                // check if **never** disposable
+                if ((type.IsValueType || type.IsSealed) &&
+                    !ctx.MapType(typeof(IDisposable)).IsAssignableFrom(type))
+                {
+                    return; // nothing to do! easiest "using" block ever
+                    // (note that C# wouldn't allow this as a "using" block,
+                    // but we'll be generous and simply not do anything)
+                }
+                this.local = local;
+                this.ctx = ctx;
+                label = ctx.BeginTry();
+                
+            }
+            public void Dispose()
+            {
+                if (local == null || ctx == null) return;
+
+                ctx.EndTry(label, false);
+                ctx.BeginFinally();
+                Type disposableType = ctx.MapType(typeof (IDisposable));
+                MethodInfo dispose = disposableType.GetMethod("Dispose");
+                Type type = local.Type;
+                // remember that we've already (in the .ctor) excluded the case
+                // where it *cannot* be disposable
+                if (type.IsValueType)
+                {
+                    ctx.LoadAddress(local, type);
+                    switch (ctx.MetadataVersion)
+                    {
+                        case ILVersion.Net1:
+                            ctx.LoadValue(local);
+                            ctx.CastToObject(type);
+                            break;
+                        default:
+#if FX11
+                            throw new NotSupportedException();
+#else
+                            ctx.Constrain(type);
+                            break;
+#endif
+                    }
+                    ctx.EmitCall(dispose);                    
+                }
+                else
+                {
+                    Compiler.CodeLabel @null = ctx.DefineLabel();
+                    if (disposableType.IsAssignableFrom(type))
+                    {   // *known* to be IDisposable; just needs a null-check                            
+                        ctx.LoadValue(local);
+                        ctx.BranchIfFalse(@null, true);
+                        ctx.LoadAddress(local, type);
+                    }
+                    else
+                    {   // *could* be IDisposable; test via "as"
+                        using (Compiler.Local disp = new Compiler.Local(ctx, disposableType))
+                        {
+                            ctx.LoadValue(local);
+                            ctx.TryCast(disposableType);
+                            ctx.CopyValue();
+                            ctx.StoreValue(disp);
+                            ctx.BranchIfFalse(@null, true);
+                            ctx.LoadAddress(disp, disposableType);
+                        }
+                    }
+                    ctx.EmitCall(dispose);
+                    ctx.MarkLabel(@null);
+                }
+                ctx.EndFinally();
+                this.local = null;
+                this.ctx = null;
+                label = new CodeLabel(); // default
+            }
+        }
+
+        internal void Add()
+        {
+            Emit(OpCodes.Add);
+        }
+
+        internal void LoadLength(Local arr, bool zeroIfNull)
+        {
+            Helpers.DebugAssert(arr.Type.IsArray && arr.Type.GetArrayRank() == 1);
+
+            if (zeroIfNull)
+            {
+                Compiler.CodeLabel notNull = DefineLabel(), done = DefineLabel();
+                LoadValue(arr);
+                CopyValue(); // optimised for non-null case
+                BranchIfTrue(notNull, true);
+                DiscardValue();
+                LoadValue(0);
+                Branch(done, true);
+                MarkLabel(notNull);
+                Emit(OpCodes.Ldlen);
+                Emit(OpCodes.Conv_I4);
+                MarkLabel(done);
+            }
+            else
+            {
+                LoadValue(arr);
+                Emit(OpCodes.Ldlen);
+                Emit(OpCodes.Conv_I4);
+            }
+        }
+
+        internal void CreateArray(Type elementType, Local length)
+        {
+            LoadValue(length);
+            il.Emit(OpCodes.Newarr, elementType);
+#if DEBUG_COMPILE
+            Helpers.DebugWriteLine(OpCodes.Newarr + ": " + elementType);
+#endif
+
+        }
+
+        internal void LoadArrayValue(Local arr, Local i)
+        {
+            Type type = arr.Type;
+            Helpers.DebugAssert(type.IsArray && arr.Type.GetArrayRank() == 1);
+            type = type.GetElementType();
+            Helpers.DebugAssert(type != null, "Not an array: " + arr.Type.FullName);
+            LoadValue(arr);
+            LoadValue(i);
+            switch(Helpers.GetTypeCode(type)) {
+                case ProtoTypeCode.SByte: Emit(OpCodes.Ldelem_I1); break;
+                case ProtoTypeCode.Int16: Emit(OpCodes.Ldelem_I2); break;
+                case ProtoTypeCode.Int32: Emit(OpCodes.Ldelem_I4); break;
+                case ProtoTypeCode.Int64: Emit(OpCodes.Ldelem_I8); break;
+
+                case ProtoTypeCode.Byte: Emit(OpCodes.Ldelem_U1); break;
+                case ProtoTypeCode.UInt16: Emit(OpCodes.Ldelem_U2); break;
+                case ProtoTypeCode.UInt32: Emit(OpCodes.Ldelem_U4); break;
+                case ProtoTypeCode.UInt64: Emit(OpCodes.Ldelem_I8); break; // odd, but this is what C# does...
+
+                case ProtoTypeCode.Single: Emit(OpCodes.Ldelem_R4); break;
+                case ProtoTypeCode.Double: Emit(OpCodes.Ldelem_R8); break;
+                default:
+                    if (type.IsValueType)
+                    {
+                        il.Emit(OpCodes.Ldelema, type);
+                        il.Emit(OpCodes.Ldobj, type);
+#if DEBUG_COMPILE
+                        Helpers.DebugWriteLine(OpCodes.Ldelema + ": " + type);
+                        Helpers.DebugWriteLine(OpCodes.Ldobj + ": " + type);
+#endif
+                    }
+                    else
+                    {
+                        Emit(OpCodes.Ldelem_Ref);
+                    }
+             
+                    break;
+            }
+            
+        }
+
+
+
+        internal void LoadValue(Type type)
+        {
+            il.Emit(OpCodes.Ldtoken, type);
+#if DEBUG_COMPILE
+            Helpers.DebugWriteLine(OpCodes.Ldtoken + ": " + type);
+#endif
+            EmitCall(MapType(typeof(System.Type)).GetMethod("GetTypeFromHandle"));
+        }
+
+        internal void ConvertToInt32(ProtoTypeCode typeCode, bool uint32Overflow)
+        {
+            switch (typeCode)
+            {
+                case ProtoTypeCode.Byte:
+                case ProtoTypeCode.SByte:
+                case ProtoTypeCode.Int16:
+                case ProtoTypeCode.UInt16:
+                    Emit(OpCodes.Conv_I4);
+                    break;
+                case ProtoTypeCode.Int32:
+                    break;
+                case ProtoTypeCode.Int64:
+                    Emit(OpCodes.Conv_Ovf_I4);
+                    break;
+                case ProtoTypeCode.UInt32:
+                    Emit(uint32Overflow ? OpCodes.Conv_Ovf_I4_Un : OpCodes.Conv_Ovf_I4);
+                    break;
+                case ProtoTypeCode.UInt64:
+                    Emit(OpCodes.Conv_Ovf_I4_Un);
+                    break;
+                default:
+                    throw new InvalidOperationException("ConvertToInt32 not implemented for: " + typeCode.ToString());
+            }
+        }
+
+        internal void ConvertFromInt32(ProtoTypeCode typeCode, bool uint32Overflow)
+        {
+            switch (typeCode)
+            {
+                case ProtoTypeCode.SByte: Emit(OpCodes.Conv_Ovf_I1); break;
+                case ProtoTypeCode.Byte: Emit(OpCodes.Conv_Ovf_U1); break;
+                case ProtoTypeCode.Int16: Emit(OpCodes.Conv_Ovf_I2); break;
+                case ProtoTypeCode.UInt16: Emit(OpCodes.Conv_Ovf_U2); break;
+                case ProtoTypeCode.Int32: break;
+                case ProtoTypeCode.UInt32: Emit(uint32Overflow ? OpCodes.Conv_Ovf_U4 : OpCodes.Conv_U4); break;
+                case ProtoTypeCode.Int64: Emit(OpCodes.Conv_I8); break;
+                case ProtoTypeCode.UInt64: Emit(OpCodes.Conv_U8); break;
+                default: throw new InvalidOperationException();
+            }
+        }
+
+        internal void LoadValue(decimal value)
+        {
+            if (value == 0M)
+            {
+                LoadValue(typeof(decimal).GetField("Zero"));
+            }
+            else
+            {
+                int[] bits = decimal.GetBits(value);
+                LoadValue(bits[0]); // lo
+                LoadValue(bits[1]); // mid
+                LoadValue(bits[2]); // hi
+                LoadValue((int)(((uint)bits[3]) >> 31)); // isNegative (bool, but int for CLI purposes)
+                LoadValue((bits[3] >> 16) & 0xFF); // scale (byte, but int for CLI purposes)
+
+                EmitCtor(MapType(typeof(decimal)), new Type[] { MapType(typeof(int)), MapType(typeof(int)), MapType(typeof(int)), MapType(typeof(bool)), MapType(typeof(byte)) });
+            }
+        }
+
+        internal void LoadValue(Guid value)
+        {
+            if (value == Guid.Empty)
+            {
+                LoadValue(typeof(Guid).GetField("Empty"));
+            }
+            else
+            { // note we're adding lots of shorts/bytes here - but at the IL level they are I4, not I1/I2 (which barely exist)
+                byte[] bytes = value.ToByteArray();
+                int i = (bytes[0]) | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24);
+                LoadValue(i);
+                short s = (short)((bytes[4]) | (bytes[5] << 8));
+                LoadValue(s);
+                s = (short)((bytes[6]) | (bytes[7] << 8));
+                LoadValue(s);
+                for (i = 8; i <= 15; i++)
+                {
+                    LoadValue(bytes[i]);
+                }
+                EmitCtor(MapType(typeof(Guid)), new Type[] { MapType(typeof(int)), MapType(typeof(short)), MapType(typeof(short)),
+                            MapType(typeof(byte)), MapType(typeof(byte)), MapType(typeof(byte)), MapType(typeof(byte)), MapType(typeof(byte)), MapType(typeof(byte)), MapType(typeof(byte)), MapType(typeof(byte)) });
+            }
+        }
+
+        //internal void LoadValue(bool value)
+        //{
+        //    Emit(value ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
+        //}
+
+        internal void LoadSerializationContext()
+        {
+            LoadReaderWriter();
+            LoadValue((isWriter ? typeof(ProtoWriter) : typeof(ProtoReader)).GetProperty("Context"));
+        }
+
+        private readonly TypeModel model;
+
+        internal Type MapType(System.Type type)
+        {
+            return model.MapType(type);
+        }
+
+        private readonly ILVersion metadataVersion;
+        public ILVersion MetadataVersion { get { return metadataVersion; } }
+        public enum ILVersion
+        {
+            Net1, Net2
+        }
+
+        internal bool AllowInternal(PropertyInfo property)
+        {
+            return NonPublic ? true : InternalsVisible(property.DeclaringType.Assembly);
+        }
+    }
+}
+#endif

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/Compiler/CompilerContext.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 3fa3f54def85eb4488cf2cbd8d118e66
+timeCreated: 1515899112
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 7 - 0
Unity/Assets/Plugins/protobuf-net/Compiler/CompilerDelegates.cs

@@ -0,0 +1,7 @@
+#if FEAT_COMPILER
+namespace ProtoBuf.Compiler
+{
+    internal delegate void ProtoSerializer(object value, ProtoWriter dest);
+    internal delegate object ProtoDeserializer(object value, ProtoReader source);
+}
+#endif

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/Compiler/CompilerDelegates.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 0f76001f4592d5d498e2ef4c6c5bf1a8
+timeCreated: 1515899112
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 70 - 0
Unity/Assets/Plugins/protobuf-net/Compiler/Local.cs

@@ -0,0 +1,70 @@
+#if FEAT_COMPILER
+using System;
+#if FEAT_IKVM
+using IKVM.Reflection.Emit;
+using Type  = IKVM.Reflection.Type;
+#else
+using System.Reflection.Emit;
+#endif
+
+namespace ProtoBuf.Compiler
+{
+    internal sealed class Local : IDisposable
+    {
+        // public static readonly Local InputValue = new Local(null, null);
+        LocalBuilder value;
+        public Type Type { get { return type; } }
+        public Local AsCopy()
+        {
+            if (ctx == null) return this; // can re-use if context-free
+            return new Local(value, this.type);
+        }
+        internal LocalBuilder Value
+        {
+            get
+            {
+                if (value == null)
+                {
+                    throw new ObjectDisposedException(GetType().Name);
+                }
+                return value;
+            }
+        }
+        CompilerContext ctx;
+        public void Dispose()
+        {
+            if (ctx != null)
+            {
+                // only *actually* dispose if this is context-bound; note that non-bound
+                // objects are cheekily re-used, and *must* be left intact agter a "using" etc
+                ctx.ReleaseToPool(value);
+                value = null; 
+                ctx = null;
+            }            
+            
+        }
+        private Local(LocalBuilder value, Type type)
+        {
+            this.value = value;
+            this.type = type;
+        }
+        private readonly Type type;
+        internal Local(Compiler.CompilerContext ctx, Type type)
+        {
+            this.ctx = ctx;
+            if (ctx != null) { value = ctx.GetFromPool(type); }
+            this.type = type;
+        }
+
+        internal bool IsSame(Local other)
+        {
+            if((object)this == (object)other) return true;
+
+            object ourVal = value; // use prop to ensure obj-disposed etc
+            return other != null && ourVal == (object)(other.value); 
+        }
+    }
+
+
+}
+#endif

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/Compiler/Local.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 0dcacd88e875d944b82e41d2a0902f79
+timeCreated: 1515899112
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 42 - 0
Unity/Assets/Plugins/protobuf-net/DataFormat.cs

@@ -0,0 +1,42 @@
+
+namespace ProtoBuf
+{
+    /// <summary>
+    /// Sub-format to use when serializing/deserializing data
+    /// </summary>
+    public enum DataFormat
+    {
+        /// <summary>
+        /// Uses the default encoding for the data-type.
+        /// </summary>
+        Default,
+
+        /// <summary>
+        /// When applied to signed integer-based data (including Decimal), this
+        /// indicates that zigzag variant encoding will be used. This means that values
+        /// with small magnitude (regardless of sign) take a small amount
+        /// of space to encode.
+        /// </summary>
+        ZigZag,
+
+        /// <summary>
+        /// When applied to signed integer-based data (including Decimal), this
+        /// indicates that two's-complement variant encoding will be used.
+        /// This means that any -ve number will take 10 bytes (even for 32-bit),
+        /// so should only be used for compatibility.
+        /// </summary>
+        TwosComplement,
+
+        /// <summary>
+        /// When applied to signed integer-based data (including Decimal), this
+        /// indicates that a fixed amount of space will be used.
+        /// </summary>
+        FixedSize,
+
+        /// <summary>
+        /// When applied to a sub-message, indicates that the value should be treated
+        /// as group-delimited.
+        /// </summary>
+        Group
+    }
+}

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/DataFormat.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: aab300bfaae2b4849838362e1a0fa44b
+timeCreated: 1515899114
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 286 - 0
Unity/Assets/Plugins/protobuf-net/Extensible.cs

@@ -0,0 +1,286 @@
+#if !NO_GENERICS
+using System.Collections.Generic;
+#endif
+using ProtoBuf.Meta;
+using System.Collections;
+
+namespace ProtoBuf
+{
+    /// <summary>
+    /// Simple base class for supporting unexpected fields allowing
+    /// for loss-less round-tips/merge, even if the data is not understod.
+    /// The additional fields are (by default) stored in-memory in a buffer.
+    /// </summary>
+    /// <remarks>As an example of an alternative implementation, you might
+    /// choose to use the file system (temporary files) as the back-end, tracking
+    /// only the paths [such an object would ideally be IDisposable and use
+    /// a finalizer to ensure that the files are removed].</remarks>
+    /// <seealso cref="IExtensible"/>
+    public abstract class Extensible : IExtensible
+    {
+        // note: not marked ProtoContract - no local state, and can't 
+        // predict sub-classes
+
+
+        private IExtension extensionObject;
+
+        IExtension IExtensible.GetExtensionObject(bool createIfMissing)
+        {
+            return GetExtensionObject(createIfMissing);
+        }
+        /// <summary>
+        /// Retrieves the <see cref="IExtension">extension</see> object for the current
+        /// instance, optionally creating it if it does not already exist.
+        /// </summary>
+        /// <param name="createIfMissing">Should a new extension object be
+        /// created if it does not already exist?</param>
+        /// <returns>The extension object if it exists (or was created), or null
+        /// if the extension object does not exist or is not available.</returns>
+        /// <remarks>The <c>createIfMissing</c> argument is false during serialization,
+        /// and true during deserialization upon encountering unexpected fields.</remarks>
+        protected virtual IExtension GetExtensionObject(bool createIfMissing)
+        {
+            return GetExtensionObject(ref extensionObject, createIfMissing);
+        }
+
+        /// <summary>
+        /// Provides a simple, default implementation for <see cref="IExtension">extension</see> support,
+        /// optionally creating it if it does not already exist. Designed to be called by
+        /// classes implementing <see cref="IExtensible"/>.
+        /// </summary>
+        /// <param name="createIfMissing">Should a new extension object be
+        /// created if it does not already exist?</param>
+        /// <param name="extensionObject">The extension field to check (and possibly update).</param>
+        /// <returns>The extension object if it exists (or was created), or null
+        /// if the extension object does not exist or is not available.</returns>
+        /// <remarks>The <c>createIfMissing</c> argument is false during serialization,
+        /// and true during deserialization upon encountering unexpected fields.</remarks>
+        public static IExtension GetExtensionObject(ref IExtension extensionObject, bool createIfMissing)
+        {
+            if (createIfMissing && extensionObject == null)
+            {
+                extensionObject = new BufferExtension();
+            }
+            return extensionObject;
+        }
+
+#if !NO_RUNTIME && !NO_GENERICS
+        /// <summary>
+        /// Appends the value as an additional (unexpected) data-field for the instance.
+        /// Note that for non-repeated sub-objects, this equates to a merge operation;
+        /// for repeated sub-objects this adds a new instance to the set; for simple
+        /// values the new value supercedes the old value.
+        /// </summary>
+        /// <remarks>Note that appending a value does not remove the old value from
+        /// the stream; avoid repeatedly appending values for the same field.</remarks>
+        /// <typeparam name="TValue">The type of the value to append.</typeparam>
+        /// <param name="instance">The extensible object to append the value to.</param>
+        /// <param name="tag">The field identifier; the tag should not be defined as a known data-field for the instance.</param>
+        /// <param name="value">The value to append.</param>
+        public static void AppendValue<TValue>(IExtensible instance, int tag, TValue value)
+        {
+            AppendValue<TValue>(instance, tag, DataFormat.Default, value);
+        }
+
+        /// <summary>
+        /// Appends the value as an additional (unexpected) data-field for the instance.
+        /// Note that for non-repeated sub-objects, this equates to a merge operation;
+        /// for repeated sub-objects this adds a new instance to the set; for simple
+        /// values the new value supercedes the old value.
+        /// </summary>
+        /// <remarks>Note that appending a value does not remove the old value from
+        /// the stream; avoid repeatedly appending values for the same field.</remarks>
+        /// <typeparam name="TValue">The data-type of the field.</typeparam>
+        /// <param name="format">The data-format to use when encoding the value.</param>
+        /// <param name="instance">The extensible object to append the value to.</param>
+        /// <param name="tag">The field identifier; the tag should not be defined as a known data-field for the instance.</param>
+        /// <param name="value">The value to append.</param>
+        public static void AppendValue<TValue>(IExtensible instance, int tag, DataFormat format, TValue value)
+        {
+            ExtensibleUtil.AppendExtendValue(RuntimeTypeModel.Default, instance, tag, format, value);
+        }
+        /// <summary>
+        /// Queries an extensible object for an additional (unexpected) data-field for the instance.
+        /// The value returned is the composed value after merging any duplicated content; if the
+        /// value is "repeated" (a list), then use GetValues instead.
+        /// </summary>
+        /// <typeparam name="TValue">The data-type of the field.</typeparam>
+        /// <param name="instance">The extensible object to obtain the value from.</param>
+        /// <param name="tag">The field identifier; the tag should not be defined as a known data-field for the instance.</param>
+        /// <returns>The effective value of the field, or the default value if not found.</returns>
+        public static TValue GetValue<TValue>(IExtensible instance, int tag)
+        {
+            return GetValue<TValue>(instance, tag, DataFormat.Default);
+        }
+
+        /// <summary>
+        /// Queries an extensible object for an additional (unexpected) data-field for the instance.
+        /// The value returned is the composed value after merging any duplicated content; if the
+        /// value is "repeated" (a list), then use GetValues instead.
+        /// </summary>
+        /// <typeparam name="TValue">The data-type of the field.</typeparam>
+        /// <param name="instance">The extensible object to obtain the value from.</param>
+        /// <param name="tag">The field identifier; the tag should not be defined as a known data-field for the instance.</param>
+        /// <param name="format">The data-format to use when decoding the value.</param>
+        /// <returns>The effective value of the field, or the default value if not found.</returns>
+        public static TValue GetValue<TValue>(IExtensible instance, int tag, DataFormat format)
+        {
+            TValue value;
+            TryGetValue<TValue>(instance, tag, format, out value);
+            return value;
+        }
+
+        /// <summary>
+        /// Queries an extensible object for an additional (unexpected) data-field for the instance.
+        /// The value returned (in "value") is the composed value after merging any duplicated content;
+        /// if the value is "repeated" (a list), then use GetValues instead.
+        /// </summary>
+        /// <typeparam name="TValue">The data-type of the field.</typeparam>
+        /// <param name="value">The effective value of the field, or the default value if not found.</param>
+        /// <param name="instance">The extensible object to obtain the value from.</param>
+        /// <param name="tag">The field identifier; the tag should not be defined as a known data-field for the instance.</param>
+        /// <returns>True if data for the field was present, false otherwise.</returns>
+        public static bool TryGetValue<TValue>(IExtensible instance, int tag, out TValue value)
+        {
+            return TryGetValue<TValue>(instance, tag, DataFormat.Default, out value);
+        }
+
+        /// <summary>
+        /// Queries an extensible object for an additional (unexpected) data-field for the instance.
+        /// The value returned (in "value") is the composed value after merging any duplicated content;
+        /// if the value is "repeated" (a list), then use GetValues instead.
+        /// </summary>
+        /// <typeparam name="TValue">The data-type of the field.</typeparam>
+        /// <param name="value">The effective value of the field, or the default value if not found.</param>
+        /// <param name="instance">The extensible object to obtain the value from.</param>
+        /// <param name="tag">The field identifier; the tag should not be defined as a known data-field for the instance.</param>
+        /// <param name="format">The data-format to use when decoding the value.</param>
+        /// <returns>True if data for the field was present, false otherwise.</returns>
+        public static bool TryGetValue<TValue>(IExtensible instance, int tag, DataFormat format, out TValue value)
+        {
+            return TryGetValue<TValue>(instance, tag, format, false, out value);
+        }
+
+        /// <summary>
+        /// Queries an extensible object for an additional (unexpected) data-field for the instance.
+        /// The value returned (in "value") is the composed value after merging any duplicated content;
+        /// if the value is "repeated" (a list), then use GetValues instead.
+        /// </summary>
+        /// <typeparam name="TValue">The data-type of the field.</typeparam>
+        /// <param name="value">The effective value of the field, or the default value if not found.</param>
+        /// <param name="instance">The extensible object to obtain the value from.</param>
+        /// <param name="tag">The field identifier; the tag should not be defined as a known data-field for the instance.</param>
+        /// <param name="format">The data-format to use when decoding the value.</param>
+        /// <param name="allowDefinedTag">Allow tags that are present as part of the definition; for example, to query unknown enum values.</param>
+        /// <returns>True if data for the field was present, false otherwise.</returns>
+        public static bool TryGetValue<TValue>(IExtensible instance, int tag, DataFormat format, bool allowDefinedTag, out TValue value)
+        {
+            value = default(TValue);
+            bool set = false;
+            foreach (TValue val in ExtensibleUtil.GetExtendedValues<TValue>(instance, tag, format, true, allowDefinedTag))
+            {
+                // expecting at most one yield...
+                // but don't break; need to read entire stream
+                value = val;
+                set = true;
+            }
+
+            return set;
+        }
+
+        /// <summary>
+        /// Queries an extensible object for an additional (unexpected) data-field for the instance.
+        /// Each occurrence of the field is yielded separately, making this usage suitable for "repeated"
+        /// (list) fields.
+        /// </summary>
+        /// <remarks>The extended data is processed lazily as the enumerator is iterated.</remarks>
+        /// <typeparam name="TValue">The data-type of the field.</typeparam>
+        /// <param name="instance">The extensible object to obtain the value from.</param>
+        /// <param name="tag">The field identifier; the tag should not be defined as a known data-field for the instance.</param>
+        /// <returns>An enumerator that yields each occurrence of the field.</returns>
+        public static IEnumerable<TValue> GetValues<TValue>(IExtensible instance, int tag)
+        {
+            return ExtensibleUtil.GetExtendedValues<TValue>(instance, tag, DataFormat.Default, false, false);
+        }
+
+        /// <summary>
+        /// Queries an extensible object for an additional (unexpected) data-field for the instance.
+        /// Each occurrence of the field is yielded separately, making this usage suitable for "repeated"
+        /// (list) fields.
+        /// </summary>
+        /// <remarks>The extended data is processed lazily as the enumerator is iterated.</remarks>
+        /// <typeparam name="TValue">The data-type of the field.</typeparam>
+        /// <param name="instance">The extensible object to obtain the value from.</param>
+        /// <param name="tag">The field identifier; the tag should not be defined as a known data-field for the instance.</param>
+        /// <param name="format">The data-format to use when decoding the value.</param>
+        /// <returns>An enumerator that yields each occurrence of the field.</returns>
+        public static IEnumerable<TValue> GetValues<TValue>(IExtensible instance, int tag, DataFormat format)
+        {
+            return ExtensibleUtil.GetExtendedValues<TValue>(instance, tag, format, false, false);
+        }
+#endif
+
+        /// <summary>
+        /// Queries an extensible object for an additional (unexpected) data-field for the instance.
+        /// The value returned (in "value") is the composed value after merging any duplicated content;
+        /// if the value is "repeated" (a list), then use GetValues instead.
+        /// </summary>
+        /// <param name="type">The data-type of the field.</param>
+        /// <param name="model">The model to use for configuration.</param>
+        /// <param name="value">The effective value of the field, or the default value if not found.</param>
+        /// <param name="instance">The extensible object to obtain the value from.</param>
+        /// <param name="tag">The field identifier; the tag should not be defined as a known data-field for the instance.</param>
+        /// <param name="format">The data-format to use when decoding the value.</param>
+        /// <param name="allowDefinedTag">Allow tags that are present as part of the definition; for example, to query unknown enum values.</param>
+        /// <returns>True if data for the field was present, false otherwise.</returns>
+        public static bool TryGetValue(TypeModel model, System.Type type, IExtensible instance, int tag, DataFormat format, bool allowDefinedTag, out object value)
+        {
+            value = null;
+            bool set = false;
+            foreach (object val in ExtensibleUtil.GetExtendedValues(model, type, instance, tag, format, true, allowDefinedTag))
+            {
+                // expecting at most one yield...
+                // but don't break; need to read entire stream
+                value = val;
+                set = true;
+            }
+
+            return set;
+        }
+        /// <summary>
+        /// Queries an extensible object for an additional (unexpected) data-field for the instance.
+        /// Each occurrence of the field is yielded separately, making this usage suitable for "repeated"
+        /// (list) fields.
+        /// </summary>
+        /// <remarks>The extended data is processed lazily as the enumerator is iterated.</remarks>
+        /// <param name="model">The model to use for configuration.</param>
+        /// <param name="type">The data-type of the field.</param>
+        /// <param name="instance">The extensible object to obtain the value from.</param>
+        /// <param name="tag">The field identifier; the tag should not be defined as a known data-field for the instance.</param>
+        /// <param name="format">The data-format to use when decoding the value.</param>
+        /// <returns>An enumerator that yields each occurrence of the field.</returns>
+        public static IEnumerable GetValues(TypeModel model, System.Type type, IExtensible instance, int tag, DataFormat format)
+        {
+            return ExtensibleUtil.GetExtendedValues(model, type, instance, tag, format, false, false);
+        }
+
+        /// <summary>
+        /// Appends the value as an additional (unexpected) data-field for the instance.
+        /// Note that for non-repeated sub-objects, this equates to a merge operation;
+        /// for repeated sub-objects this adds a new instance to the set; for simple
+        /// values the new value supercedes the old value.
+        /// </summary>
+        /// <remarks>Note that appending a value does not remove the old value from
+        /// the stream; avoid repeatedly appending values for the same field.</remarks>
+        /// <param name="model">The model to use for configuration.</param>
+        /// <param name="format">The data-format to use when encoding the value.</param>
+        /// <param name="instance">The extensible object to append the value to.</param>
+        /// <param name="tag">The field identifier; the tag should not be defined as a known data-field for the instance.</param>
+        /// <param name="value">The value to append.</param>
+        public static void AppendValue(TypeModel model, IExtensible instance, int tag, DataFormat format, object value)
+        {
+            ExtensibleUtil.AppendExtendValue(model, instance, tag, format, value);
+        }
+        
+    }   
+}

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/Extensible.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 77c8983bf441b92468a08431a347d975
+timeCreated: 1515899113
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 151 - 0
Unity/Assets/Plugins/protobuf-net/ExtensibleUtil.cs

@@ -0,0 +1,151 @@
+using System;
+using System.Collections;
+#if !NO_GENERICS
+using System.Collections.Generic;
+#endif
+using System.IO;
+using ProtoBuf.Meta;
+
+namespace ProtoBuf
+{
+    /// <summary>
+    /// This class acts as an internal wrapper allowing us to do a dynamic
+    /// methodinfo invoke; an't put into Serializer as don't want on public
+    /// API; can't put into Serializer&lt;T&gt; since we need to invoke
+    /// accross classes, which isn't allowed in Silverlight)
+    /// </summary>
+    internal
+#if FX11
+    sealed
+#else
+    static
+#endif
+        class ExtensibleUtil
+    {
+#if FX11
+        private ExtensibleUtil() { } // not a static class for C# 1.2 reasons
+#endif
+
+#if !NO_RUNTIME && !NO_GENERICS
+        /// <summary>
+        /// All this does is call GetExtendedValuesTyped with the correct type for "instance";
+        /// this ensures that we don't get issues with subclasses declaring conflicting types -
+        /// the caller must respect the fields defined for the type they pass in.
+        /// </summary>
+        internal static IEnumerable<TValue> GetExtendedValues<TValue>(IExtensible instance, int tag, DataFormat format, bool singleton, bool allowDefinedTag)
+        {
+            foreach (TValue value in GetExtendedValues(RuntimeTypeModel.Default, typeof(TValue), instance, tag, format, singleton, allowDefinedTag))
+            {
+                yield return value;
+            }
+        }
+#endif
+        /// <summary>
+        /// All this does is call GetExtendedValuesTyped with the correct type for "instance";
+        /// this ensures that we don't get issues with subclasses declaring conflicting types -
+        /// the caller must respect the fields defined for the type they pass in.
+        /// </summary>
+        internal static IEnumerable GetExtendedValues(TypeModel model, Type type, IExtensible instance, int tag, DataFormat format, bool singleton, bool allowDefinedTag)
+        {
+#if FEAT_IKVM
+            throw new NotSupportedException();
+#else
+
+            if (instance == null) throw new ArgumentNullException("instance");
+            if (tag <= 0) throw new ArgumentOutOfRangeException("tag");
+            IExtension extn = instance.GetExtensionObject(false);
+
+            if (extn == null)
+            {
+#if FX11
+                return new object[0];
+#else
+                yield break;
+#endif
+            }
+
+#if FX11
+            BasicList result = new BasicList();
+#endif
+            Stream stream = extn.BeginQuery();
+            object value = null;
+            ProtoReader reader = null;
+            try {
+                SerializationContext ctx = new SerializationContext();
+                reader = ProtoReader.Create(stream, model, ctx, ProtoReader.TO_EOF);
+                while (model.TryDeserializeAuxiliaryType(reader, format, tag, type, ref value, true, false, false, false) && value != null)
+                {
+                    if (!singleton)
+                    {
+#if FX11
+                        result.Add(value);
+#else
+                        yield return value;
+#endif
+                        value = null; // fresh item each time
+                    }
+                }
+                if (singleton && value != null)
+                {
+#if FX11
+                    result.Add(value);
+#else
+                    yield return value;
+#endif
+                }
+#if FX11
+                object[] resultArr = new object[result.Count];
+                result.CopyTo(resultArr, 0);
+                return resultArr;
+#endif
+            } finally {
+                ProtoReader.Recycle(reader);
+                extn.EndQuery(stream);
+            }
+#endif       
+        }
+
+        internal static void AppendExtendValue(TypeModel model, IExtensible instance, int tag, DataFormat format, object value)
+        {
+#if FEAT_IKVM
+            throw new NotSupportedException();
+#else
+            if(instance == null) throw new ArgumentNullException("instance");
+            if(value == null) throw new ArgumentNullException("value");
+
+            // TODO
+            //model.CheckTagNotInUse(tag);
+
+            // obtain the extension object and prepare to write
+            IExtension extn = instance.GetExtensionObject(true);
+            if (extn == null) throw new InvalidOperationException("No extension object available; appended data would be lost.");
+            bool commit = false;
+            Stream stream = extn.BeginAppend();
+            try {
+                using(ProtoWriter writer = new ProtoWriter(stream, model, null)) {
+                    model.TrySerializeAuxiliaryType(writer, null, format, tag, value, false);
+                    writer.Close();
+                }
+                commit = true;
+            }
+            finally {
+                extn.EndAppend(stream, commit);
+            }
+#endif
+        }
+//#if !NO_GENERICS
+//        /// <summary>
+//        /// Stores the given value into the instance's stream; the serializer
+//        /// is inferred from TValue and format.
+//        /// </summary>
+//        /// <remarks>Needs to be public to be callable thru reflection in Silverlight</remarks>
+//        public static void AppendExtendValueTyped<TSource, TValue>(
+//            TypeModel model, TSource instance, int tag, DataFormat format, TValue value)
+//            where TSource : class, IExtensible
+//        {
+//            AppendExtendValue(model, instance, tag, format, value);
+//        }
+//#endif
+    }
+
+}

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/ExtensibleUtil.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 211105008660eb04e95682d31cbb4430
+timeCreated: 1515899112
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Unity/Assets/Plugins/protobuf-net/GlobalSuppressions.cs


+ 12 - 0
Unity/Assets/Plugins/protobuf-net/GlobalSuppressions.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: e2c9fa3fac1ee3e4eba16c0ccc6d7794
+timeCreated: 1515899114
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 601 - 0
Unity/Assets/Plugins/protobuf-net/Helpers.cs

@@ -0,0 +1,601 @@
+
+using System;
+using System.Collections;
+
+#if FEAT_IKVM
+using Type = IKVM.Reflection.Type;
+using IKVM.Reflection;
+#else
+using System.Reflection;
+#endif
+
+namespace ProtoBuf
+{
+    /// <summary>
+    /// Not all frameworks are created equal (fx1.1 vs fx2.0,
+    /// micro-framework, compact-framework,
+    /// silverlight, etc). This class simply wraps up a few things that would
+    /// otherwise make the real code unnecessarily messy, providing fallback
+    /// implementations if necessary.
+    /// </summary>
+    internal sealed class Helpers
+    {
+        private Helpers() { }
+
+        public static System.Text.StringBuilder AppendLine(System.Text.StringBuilder builder)
+        {
+#if CF2
+            return builder.Append("\r\n");
+#elif FX11
+            return builder.Append(Environment.NewLine);
+#else
+            return builder.AppendLine();
+#endif
+        }
+        public static bool IsNullOrEmpty(string value)
+        { // yes, FX11 lacks this!
+            return value == null || value.Length == 0;
+        }
+
+        [System.Diagnostics.Conditional("DEBUG")]
+        public static void DebugWriteLine(string message, object obj)
+        {
+#if DEBUG
+            string suffix;
+            try
+            {
+                suffix = obj == null ? "(null)" : obj.ToString();
+            }
+            catch
+            {
+                suffix = "(exception)";
+            }
+            DebugWriteLine(message + ": " + suffix);
+#endif
+        }
+        [System.Diagnostics.Conditional("DEBUG")]
+        public static void DebugWriteLine(string message)
+        {
+#if DEBUG
+#if MF      
+            Microsoft.SPOT.Debug.Print(message);
+#else
+            System.Diagnostics.Debug.WriteLine(message);
+#endif
+#endif
+        }
+        [System.Diagnostics.Conditional("TRACE")]
+        public static void TraceWriteLine(string message)
+        {
+#if TRACE
+#if MF
+            Microsoft.SPOT.Trace.Print(message);
+#elif SILVERLIGHT || MONODROID || CF2 || WINRT || IOS || PORTABLE
+            System.Diagnostics.Debug.WriteLine(message);
+#else
+            System.Diagnostics.Trace.WriteLine(message);
+#endif
+#endif
+        }
+
+        [System.Diagnostics.Conditional("DEBUG")]
+        public static void DebugAssert(bool condition, string message)
+        {
+#if DEBUG
+            if (!condition)
+            {
+#if MF
+                Microsoft.SPOT.Debug.Assert(false, message);
+#else
+                System.Diagnostics.Debug.Assert(false, message);
+            }
+#endif
+#endif
+        }
+        [System.Diagnostics.Conditional("DEBUG")]
+        public static void DebugAssert(bool condition, string message, params object[] args)
+        {
+#if DEBUG
+            if (!condition) DebugAssert(false, string.Format(message, args));
+#endif
+        }
+        [System.Diagnostics.Conditional("DEBUG")]
+        public static void DebugAssert(bool condition)
+        {
+#if DEBUG   
+#if MF
+            Microsoft.SPOT.Debug.Assert(condition);
+#else
+            if(!condition && System.Diagnostics.Debugger.IsAttached) System.Diagnostics.Debugger.Break();
+            System.Diagnostics.Debug.Assert(condition);
+#endif
+#endif
+        }
+#if !NO_RUNTIME
+        public static void Sort(int[] keys, object[] values)
+        {
+            // bubble-sort; it'll work on MF, has small code,
+            // and works well-enough for our sizes. This approach
+            // also allows us to do `int` compares without having
+            // to go via IComparable etc, so win:win
+            bool swapped;
+            do {
+                swapped = false;
+                for (int i = 1; i < keys.Length; i++) {
+                    if (keys[i - 1] > keys[i]) {
+                        int tmpKey = keys[i];
+                        keys[i] = keys[i - 1];
+                        keys[i - 1] = tmpKey;
+                        object tmpValue = values[i];
+                        values[i] = values[i - 1];
+                        values[i - 1] = tmpValue;
+                        swapped = true;
+                    }
+                }
+            } while (swapped);
+        }
+#endif
+        public static void BlockCopy(byte[] from, int fromIndex, byte[] to, int toIndex, int count)
+        {
+#if MF || WINRT
+            Array.Copy(from, fromIndex, to, toIndex, count);
+#else
+            Buffer.BlockCopy(from, fromIndex, to, toIndex, count);
+#endif
+        }
+        public static bool IsInfinity(float value)
+        {
+#if MF
+            const float inf = (float)1.0 / (float)0.0, minf = (float)-1.0F / (float)0.0;
+            return value == inf || value == minf;
+#else
+            return float.IsInfinity(value);
+#endif
+        }
+#if WINRT
+        internal static MemberInfo GetInstanceMember(TypeInfo declaringType, string name)
+        {
+            PropertyInfo prop = declaringType.GetDeclaredProperty(name);
+            MethodInfo method;
+            if (prop != null && (method = Helpers.GetGetMethod(prop, true, true)) != null && !method.IsStatic) return prop;
+
+            FieldInfo field = declaringType.GetDeclaredField(name);
+            if (field != null && !field.IsStatic) return field;
+
+            return null;
+        }
+        internal static MethodInfo GetInstanceMethod(TypeInfo declaringType, string name)
+        {
+            foreach (MethodInfo method in declaringType.DeclaredMethods)
+            {
+                if (!method.IsStatic && method.Name == name)
+                {
+                    return method;
+                }
+            }
+            return null;
+        }
+        internal static MethodInfo GetStaticMethod(TypeInfo declaringType, string name)
+        {
+            foreach (MethodInfo method in declaringType.DeclaredMethods)
+            {
+                if (method.IsStatic && method.Name == name)
+                {
+                    return method;
+                }
+            }
+            return null;
+        }
+        internal static MethodInfo GetInstanceMethod(Type declaringType, string name, Type[] types)
+        {
+            return GetInstanceMethod(declaringType.GetTypeInfo(), name, types);
+        }
+        internal static MethodInfo GetInstanceMethod(TypeInfo declaringType, string name, Type[] types)
+        {
+            if (types == null) types = EmptyTypes;
+            foreach (MethodInfo method in declaringType.DeclaredMethods)
+            {
+                if (!method.IsStatic && method.Name == name)
+                {
+                    if(IsMatch(method.GetParameters(), types)) return method;
+                }
+            }
+            return null;
+        }
+#else
+        internal static MethodInfo GetInstanceMethod(Type declaringType, string name)
+        {
+            return declaringType.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
+        }
+        internal static MethodInfo GetStaticMethod(Type declaringType, string name)
+        {
+            return declaringType.GetMethod(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
+        }
+        internal static MethodInfo GetInstanceMethod(Type declaringType, string name, Type[] types)
+        {
+            if(types == null) types = EmptyTypes;
+#if PORTABLE
+            MethodInfo method = declaringType.GetMethod(name, types);
+            if (method != null && method.IsStatic) method = null;
+            return method;
+#else
+            return declaringType.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
+                null, types, null);
+#endif
+        }
+#endif
+
+        internal static bool IsSubclassOf(Type type, Type baseClass)
+        {
+#if WINRT
+            return type.GetTypeInfo().IsSubclassOf(baseClass);
+#else
+            return type.IsSubclassOf(baseClass);
+#endif
+        }
+
+        public static bool IsInfinity(double value)
+        {
+#if MF
+            const double inf = (double)1.0 / (double)0.0, minf = (double)-1.0F / (double)0.0;
+            return value == inf || value == minf;
+#else
+            return double.IsInfinity(value);
+#endif
+        }
+        public readonly static Type[] EmptyTypes =
+#if PORTABLE || WINRT || CF2 || CF35
+            new Type[0];
+#else
+            Type.EmptyTypes;
+#endif
+
+#if WINRT
+        private static readonly Type[] knownTypes = new Type[] {
+                typeof(bool), typeof(char), typeof(sbyte), typeof(byte),
+                typeof(short), typeof(ushort), typeof(int), typeof(uint),
+                typeof(long), typeof(ulong), typeof(float), typeof(double),
+                typeof(decimal), typeof(string),
+                typeof(DateTime), typeof(TimeSpan), typeof(Guid), typeof(Uri),
+                typeof(byte[]), typeof(System.Type)};
+        private static readonly ProtoTypeCode[] knownCodes = new ProtoTypeCode[] {
+            ProtoTypeCode.Boolean, ProtoTypeCode.Char, ProtoTypeCode.SByte, ProtoTypeCode.Byte,
+            ProtoTypeCode.Int16, ProtoTypeCode.UInt16, ProtoTypeCode.Int32, ProtoTypeCode.UInt32,
+            ProtoTypeCode.Int64, ProtoTypeCode.UInt64, ProtoTypeCode.Single, ProtoTypeCode.Double,
+            ProtoTypeCode.Decimal, ProtoTypeCode.String,
+            ProtoTypeCode.DateTime, ProtoTypeCode.TimeSpan, ProtoTypeCode.Guid, ProtoTypeCode.Uri,
+            ProtoTypeCode.ByteArray, ProtoTypeCode.Type
+        };
+
+#endif
+
+#if FEAT_IKVM
+        public static ProtoTypeCode GetTypeCode(IKVM.Reflection.Type type)
+        {
+            TypeCode code = IKVM.Reflection.Type.GetTypeCode(type);
+            switch (code)
+            {
+                case TypeCode.Empty:
+                case TypeCode.Boolean:
+                case TypeCode.Char:
+                case TypeCode.SByte:
+                case TypeCode.Byte:
+                case TypeCode.Int16:
+                case TypeCode.UInt16:
+                case TypeCode.Int32:
+                case TypeCode.UInt32:
+                case TypeCode.Int64:
+                case TypeCode.UInt64:
+                case TypeCode.Single:
+                case TypeCode.Double:
+                case TypeCode.Decimal:
+                case TypeCode.DateTime:
+                case TypeCode.String:
+                    return (ProtoTypeCode)code;
+            }
+            switch(type.FullName)
+            {
+                case "System.TimeSpan": return ProtoTypeCode.TimeSpan;
+                case "System.Guid": return ProtoTypeCode.Guid;
+                case "System.Uri": return ProtoTypeCode.Uri;
+                case "System.Byte[]": return ProtoTypeCode.ByteArray;
+                case "System.Type": return ProtoTypeCode.Type;
+            }
+            return ProtoTypeCode.Unknown;
+        }
+#endif
+
+        public static ProtoTypeCode GetTypeCode(System.Type type)
+        {
+#if WINRT
+            
+            int idx = Array.IndexOf<Type>(knownTypes, type);
+            if (idx >= 0) return knownCodes[idx];
+            return type == null ? ProtoTypeCode.Empty : ProtoTypeCode.Unknown;
+#else
+            TypeCode code = System.Type.GetTypeCode(type);
+            switch (code)
+            {
+                case TypeCode.Empty:
+                case TypeCode.Boolean:
+                case TypeCode.Char:
+                case TypeCode.SByte:
+                case TypeCode.Byte:
+                case TypeCode.Int16:
+                case TypeCode.UInt16:
+                case TypeCode.Int32:
+                case TypeCode.UInt32:
+                case TypeCode.Int64:
+                case TypeCode.UInt64:
+                case TypeCode.Single:
+                case TypeCode.Double:
+                case TypeCode.Decimal:
+                case TypeCode.DateTime:
+                case TypeCode.String:
+                    return (ProtoTypeCode)code;
+            }
+            if (type == typeof(TimeSpan)) return ProtoTypeCode.TimeSpan;
+            if (type == typeof(Guid)) return ProtoTypeCode.Guid;
+            if (type == typeof(Uri)) return ProtoTypeCode.Uri;
+            if (type == typeof(byte[])) return ProtoTypeCode.ByteArray;
+            if (type == typeof(System.Type)) return ProtoTypeCode.Type;
+
+            return ProtoTypeCode.Unknown;
+#endif
+        }
+
+        
+#if FEAT_IKVM
+        internal static IKVM.Reflection.Type GetUnderlyingType(IKVM.Reflection.Type type)
+        {
+            if (type.IsValueType && type.IsGenericType && type.GetGenericTypeDefinition().FullName == "System.Nullable`1")
+            {
+                return type.GetGenericArguments()[0];
+            }
+            return null;
+        }
+#endif
+
+        internal static System.Type GetUnderlyingType(System.Type type)
+        {
+#if NO_GENERICS
+            return null; // never a Nullable<T>, so always returns null
+#else
+            return Nullable.GetUnderlyingType(type);
+#endif
+        }
+
+        internal static bool IsValueType(Type type)
+        {
+#if WINRT
+            return type.GetTypeInfo().IsValueType;
+#else
+            return type.IsValueType;
+#endif
+        }
+
+        internal static bool IsEnum(Type type)
+        {
+#if WINRT
+            return type.GetTypeInfo().IsEnum;
+#else
+            return type.IsEnum;
+#endif
+        }
+
+        internal static MethodInfo GetGetMethod(PropertyInfo property, bool nonPublic, bool allowInternal)
+        {
+            if (property == null) return null;
+#if WINRT
+            MethodInfo method = property.GetMethod;
+            if (!nonPublic && method != null && !method.IsPublic) method = null;
+            return method;
+#else
+            MethodInfo method = property.GetGetMethod(nonPublic);
+            if (method == null && !nonPublic && allowInternal)
+            { // could be "internal" or "protected internal"; look for a non-public, then back-check
+                method = property.GetGetMethod(true);
+                if (method == null && !(method.IsAssembly || method.IsFamilyOrAssembly))
+                {
+                    method = null;
+                }
+            }
+            return method;
+#endif
+        }
+        internal static MethodInfo GetSetMethod(PropertyInfo property, bool nonPublic, bool allowInternal)
+        {
+            if (property == null) return null;
+#if WINRT
+            MethodInfo method = property.SetMethod;
+            if (!nonPublic && method != null && !method.IsPublic) method = null;
+            return method;
+#else
+            MethodInfo method = property.GetSetMethod(nonPublic);
+            if (method == null && !nonPublic && allowInternal)
+            { // could be "internal" or "protected internal"; look for a non-public, then back-check
+                method = property.GetGetMethod(true);
+                if (method == null && !(method.IsAssembly || method.IsFamilyOrAssembly))
+                {
+                    method = null;
+                }
+            }
+            return method;
+#endif
+        }
+
+#if FEAT_IKVM
+        internal static bool IsMatch(IKVM.Reflection.ParameterInfo[] parameters, IKVM.Reflection.Type[] parameterTypes)
+        {
+            if (parameterTypes == null) parameterTypes = Helpers.EmptyTypes;
+            if (parameters.Length != parameterTypes.Length) return false;
+            for (int i = 0; i < parameters.Length; i++)
+            {
+                if (parameters[i].ParameterType != parameterTypes[i]) return false;
+            }
+            return true;
+        }
+#endif
+#if WINRT
+        private static bool IsMatch(ParameterInfo[] parameters, Type[] parameterTypes)
+        {
+            if (parameterTypes == null) parameterTypes = EmptyTypes;
+            if (parameters.Length != parameterTypes.Length) return false;
+            for (int i = 0; i < parameters.Length; i++)
+            {
+                if (parameters[i].ParameterType != parameterTypes[i]) return false;
+            }
+            return true;
+        }
+        internal static ConstructorInfo GetConstructor(TypeInfo type, Type[] parameterTypes, bool nonPublic)
+        {
+            foreach (ConstructorInfo ctor in type.DeclaredConstructors)
+            {
+                if (!nonPublic && !ctor.IsPublic) continue;
+                if (IsMatch(ctor.GetParameters(), parameterTypes)) return ctor;
+            }
+            return null;
+        }
+        internal static ConstructorInfo[] GetConstructors(TypeInfo typeInfo, bool nonPublic)
+        {
+            if (nonPublic) return System.Linq.Enumerable.ToArray(typeInfo.DeclaredConstructors);
+            return System.Linq.Enumerable.ToArray(
+                System.Linq.Enumerable.Where(typeInfo.DeclaredConstructors, x => x.IsPublic));
+        }
+        internal static PropertyInfo GetProperty(TypeInfo type, string name, bool nonPublic)
+        {
+            return type.GetDeclaredProperty(name);
+        }
+#else
+
+        internal static ConstructorInfo GetConstructor(Type type, Type[] parameterTypes, bool nonPublic)
+        {
+#if PORTABLE
+            // pretty sure this will only ever return public, but...
+            ConstructorInfo ctor = type.GetConstructor(parameterTypes);
+            return (ctor != null && (nonPublic || ctor.IsPublic)) ? ctor : null;
+#else
+            return type.GetConstructor(
+                nonPublic ? BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
+                          : BindingFlags.Instance | BindingFlags.Public,
+                    null, parameterTypes, null);
+#endif
+
+        }
+        internal static ConstructorInfo[] GetConstructors(Type type, bool nonPublic)
+        {
+            return type.GetConstructors(
+                nonPublic ? BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
+                          : BindingFlags.Instance | BindingFlags.Public);
+        }
+        internal static PropertyInfo GetProperty(Type type, string name, bool nonPublic)
+        {
+            return type.GetProperty(name,
+                nonPublic ? BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
+                          : BindingFlags.Instance | BindingFlags.Public);
+        }
+#endif
+
+
+        internal static object ParseEnum(Type type, string value)
+        {
+#if FEAT_IKVM
+            FieldInfo[] fields = type.GetFields();
+            foreach (FieldInfo field in fields)
+            {
+                if (string.Equals(field.Name, value, StringComparison.OrdinalIgnoreCase)) return field.GetRawConstantValue();
+            }
+            throw new ArgumentException("Enum value could not be parsed: " + value + ", " + type.FullName);
+#else
+            return Enum.Parse(type, value, true);
+#endif
+        }
+
+
+        internal static MemberInfo[] GetInstanceFieldsAndProperties(Type type, bool publicOnly)
+        {
+#if WINRT
+            System.Collections.Generic.List<MemberInfo> members = new System.Collections.Generic.List<MemberInfo>();
+            foreach(FieldInfo field in type.GetRuntimeFields())
+            {
+                if(field.IsStatic) continue;
+                if(field.IsPublic || !publicOnly) members.Add(field);
+            }
+            foreach(PropertyInfo prop in type.GetRuntimeProperties())
+            {
+                MethodInfo getter = Helpers.GetGetMethod(prop, true, true);
+                if(getter == null || getter.IsStatic) continue;
+                if(getter.IsPublic || !publicOnly) members.Add(prop);
+            }
+            return members.ToArray();
+#else
+            BindingFlags flags = publicOnly ? BindingFlags.Public | BindingFlags.Instance : BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic;
+            PropertyInfo[] props = type.GetProperties(flags);
+            FieldInfo[] fields = type.GetFields(flags);
+            MemberInfo[] members = new MemberInfo[fields.Length + props.Length];
+            props.CopyTo(members, 0);
+            fields.CopyTo(members, props.Length);
+            return members;
+#endif
+        }
+
+        internal static Type GetMemberType(MemberInfo member)
+        {
+#if WINRT || PORTABLE
+            PropertyInfo prop = member as PropertyInfo;
+            if (prop != null) return prop.PropertyType;
+            FieldInfo fld = member as FieldInfo;
+            return fld == null ? null : fld.FieldType;
+#else
+            switch(member.MemberType)
+            {
+                case MemberTypes.Field: return ((FieldInfo) member).FieldType;
+                case MemberTypes.Property: return ((PropertyInfo) member).PropertyType;
+                default: return null;
+            }
+#endif
+        }
+
+        internal static bool IsAssignableFrom(Type target, Type type)
+        {
+#if WINRT
+            return target.GetTypeInfo().IsAssignableFrom(type.GetTypeInfo());
+#else
+            return target.IsAssignableFrom(type);
+#endif
+        }
+
+    }
+    /// <summary>
+    /// Intended to be a direct map to regular TypeCode, but:
+    /// - with missing types
+    /// - existing on WinRT
+    /// </summary>
+    internal enum ProtoTypeCode
+    {
+        Empty = 0,
+        Unknown = 1, // maps to TypeCode.Object
+        Boolean = 3,
+        Char = 4,
+        SByte = 5,
+        Byte = 6,
+        Int16 = 7,
+        UInt16 = 8,
+        Int32 = 9,
+        UInt32 = 10,
+        Int64 = 11,
+        UInt64 = 12,
+        Single = 13,
+        Double = 14,
+        Decimal = 15,
+        DateTime = 16,
+        String = 18,
+
+        // additions
+        TimeSpan = 100,
+        ByteArray = 101,
+        Guid = 102,
+        Uri = 103,
+        Type = 104
+    }
+}

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/Helpers.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: de5f728a0785a6f4ea8ace112c87e3f4
+timeCreated: 1515899114
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 27 - 0
Unity/Assets/Plugins/protobuf-net/IExtensible.cs

@@ -0,0 +1,27 @@
+
+namespace ProtoBuf
+{
+
+    
+    /// <summary>
+    /// Indicates that the implementing type has support for protocol-buffer
+    /// <see cref="IExtension">extensions</see>.
+    /// </summary>
+    /// <remarks>Can be implemented by deriving from Extensible.</remarks>
+    public interface IExtensible
+    {
+        /// <summary>
+        /// Retrieves the <see cref="IExtension">extension</see> object for the current
+        /// instance, optionally creating it if it does not already exist.
+        /// </summary>
+        /// <param name="createIfMissing">Should a new extension object be
+        /// created if it does not already exist?</param>
+        /// <returns>The extension object if it exists (or was created), or null
+        /// if the extension object does not exist or is not available.</returns>
+        /// <remarks>The <c>createIfMissing</c> argument is false during serialization,
+        /// and true during deserialization upon encountering unexpected fields.</remarks>
+        IExtension GetExtensionObject(bool createIfMissing);
+    }
+
+    
+}

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/IExtensible.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 894b4ee53fcbde940a50299693252ab8
+timeCreated: 1515899113
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 47 - 0
Unity/Assets/Plugins/protobuf-net/IExtension.cs

@@ -0,0 +1,47 @@
+
+using System.IO;
+namespace ProtoBuf
+{
+    /// <summary>
+    /// Provides addition capability for supporting unexpected fields during
+    /// protocol-buffer serialization/deserialization. This allows for loss-less
+    /// round-trip/merge, even when the data is not fully understood.
+    /// </summary>
+    public interface IExtension
+    {
+        /// <summary>
+        /// Requests a stream into which any unexpected fields can be persisted.
+        /// </summary>
+        /// <returns>A new stream suitable for storing data.</returns>
+        Stream BeginAppend();
+
+        /// <summary>
+        /// Indicates that all unexpected fields have now been stored. The
+        /// implementing class is responsible for closing the stream. If
+        /// "commit" is not true the data may be discarded.
+        /// </summary>
+        /// <param name="stream">The stream originally obtained by BeginAppend.</param>
+        /// <param name="commit">True if the append operation completed successfully.</param>
+        void EndAppend(Stream stream, bool commit);
+
+        /// <summary>
+        /// Requests a stream of the unexpected fields previously stored.
+        /// </summary>
+        /// <returns>A prepared stream of the unexpected fields.</returns>
+        Stream BeginQuery();
+
+        /// <summary>
+        /// Indicates that all unexpected fields have now been read. The
+        /// implementing class is responsible for closing the stream.
+        /// </summary>
+        /// <param name="stream">The stream originally obtained by BeginQuery.</param>
+        void EndQuery(Stream stream);
+
+        /// <summary>
+        /// Requests the length of the raw binary stream; this is used
+        /// when serializing sub-entities to indicate the expected size.
+        /// </summary>
+        /// <returns>The length of the binary stream representing unexpected data.</returns>
+        int GetLength();
+    }
+}

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/IExtension.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 862151bfca11b9b45b582315f7e87b60
+timeCreated: 1515899113
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 31 - 0
Unity/Assets/Plugins/protobuf-net/ImplicitFields.cs

@@ -0,0 +1,31 @@
+using System;
+
+namespace ProtoBuf
+{
+    /// <summary>
+    /// Specifies the method used to infer field tags for members of the type
+    /// under consideration. Tags are deduced using the invariant alphabetic
+    /// sequence of the members' names; this makes implicit field tags very brittle,
+    /// and susceptible to changes such as field names (normally an isolated
+    /// change).
+    /// </summary>
+    public enum ImplicitFields
+    {
+        /// <summary>
+        /// No members are serialized implicitly; all members require a suitable
+        /// attribute such as [ProtoMember]. This is the recmomended mode for
+        /// most scenarios.
+        /// </summary>
+        None = 0,
+        /// <summary>
+        /// Public properties and fields are eligible for implicit serialization;
+        /// this treats the public API as a contract. Ordering beings from ImplicitFirstTag.
+        /// </summary>
+        AllPublic= 1,
+        /// <summary>
+        /// Public and non-public fields are eligible for implicit serialization;
+        /// this acts as a state/implementation serializer. Ordering beings from ImplicitFirstTag.
+        /// </summary>
+        AllFields = 2
+    }
+}

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/ImplicitFields.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 8fab61a3c17d23f46ac0a6a4af26b42b
+timeCreated: 1515899113
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 46 - 0
Unity/Assets/Plugins/protobuf-net/KeyValuePairProxy.cs

@@ -0,0 +1,46 @@
+//#if !NO_GENERICS
+//using System.Collections.Generic;
+
+//namespace ProtoBuf
+//{
+//    /// <summary>
+//    /// Mutable version of the common key/value pair struct; used during serialization. This type is intended for internal use only and should not
+//    /// be used by calling code; it is required to be public for implementation reasons.
+//    /// </summary>
+//    [ProtoContract]
+//    public struct KeyValuePairSurrogate<TKey,TValue>
+//    {
+//        private TKey key;
+//        private TValue value;
+//        /// <summary>
+//        /// The key of the pair.
+//        /// </summary>
+//        [ProtoMember(1, IsRequired = true)]
+//        public TKey Key { get { return key; } set { key = value; } }
+//        /// <summary>
+//        /// The value of the pair.
+//        /// </summary>
+//        [ProtoMember(2)]
+//        public TValue Value{ get { return value; } set { this.value = value; } }
+//        private KeyValuePairSurrogate(TKey key, TValue value)
+//        {
+//            this.key = key;
+//            this.value = value;
+//        }
+//        /// <summary>
+//        /// Convert a surrogate instance to a standard pair instance.
+//        /// </summary>
+//        public static implicit operator KeyValuePair<TKey, TValue> (KeyValuePairSurrogate<TKey, TValue> value)
+//        {
+//            return new KeyValuePair<TKey,TValue>(value.key, value.value);
+//        }
+//        /// <summary>
+//        /// Convert a standard pair instance to a surrogate instance.
+//        /// </summary>
+//        public static implicit operator KeyValuePairSurrogate<TKey, TValue>(KeyValuePair<TKey, TValue> value)
+//        {
+//            return new KeyValuePairSurrogate<TKey, TValue>(value.Key, value.Value);
+//        }
+//    }
+//}
+//#endif

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/KeyValuePairProxy.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 21371fef76d30f345973acb5a3b3bae9
+timeCreated: 1515899112
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 3 - 3
Unity/Assets/Plugins/protobuf-net/Meta.meta

@@ -1,8 +1,8 @@
 fileFormatVersion: 2
-guid: bf303b16a9b85f446943a098b2e41c37
+guid: 1473358c6161ad14889452b663dbe0d7
 folderAsset: yes
-timeCreated: 1513686875
-licenseType: Free
+timeCreated: 1515899111
+licenseType: Pro
 DefaultImporter:
   userData: 
   assetBundleName: 

+ 191 - 0
Unity/Assets/Plugins/protobuf-net/Meta/AttributeMap.cs

@@ -0,0 +1,191 @@
+#if !NO_RUNTIME
+using System;
+#if FEAT_IKVM
+using Type = IKVM.Reflection.Type;
+using IKVM.Reflection;
+#else
+using System.Reflection;
+#endif
+
+namespace ProtoBuf.Meta
+{
+    internal abstract class AttributeMap
+    {
+#if DEBUG
+        [Obsolete("Please use AttributeType instead")]
+        new public Type GetType() { return AttributeType; }
+#endif
+        public abstract bool TryGet(string key, bool publicOnly, out object value);
+        public bool TryGet(string key, out object value)
+        {
+            return TryGet(key, true, out value);
+        }
+        public abstract Type AttributeType { get; }
+        public static AttributeMap[] Create(TypeModel model, Type type, bool inherit)
+        {
+#if FEAT_IKVM
+            Type attribType = model.MapType(typeof(System.Attribute));
+            System.Collections.Generic.IList<CustomAttributeData> all = type.__GetCustomAttributes(attribType, inherit);
+            AttributeMap[] result = new AttributeMap[all.Count];
+            int index = 0;
+            foreach (CustomAttributeData attrib in all)
+            {
+                result[index++] = new AttributeDataMap(attrib);
+            }
+            return result;
+#else
+#if WINRT
+            Attribute[] all = System.Linq.Enumerable.ToArray(type.GetTypeInfo().GetCustomAttributes(inherit));
+#else
+            object[] all = type.GetCustomAttributes(inherit);
+#endif
+            AttributeMap[] result = new AttributeMap[all.Length];
+            for(int i = 0 ; i < all.Length ; i++)
+            {
+                result[i] = new ReflectionAttributeMap((Attribute)all[i]);
+            }
+            return result;
+#endif
+        }
+
+        public static AttributeMap[] Create(TypeModel model, MemberInfo member, bool inherit)
+        {
+#if FEAT_IKVM
+            System.Collections.Generic.IList<CustomAttributeData> all = member.__GetCustomAttributes(model.MapType(typeof(Attribute)), inherit);
+            AttributeMap[] result = new AttributeMap[all.Count];
+            int index = 0;
+            foreach (CustomAttributeData attrib in all)
+            {
+                result[index++] = new AttributeDataMap(attrib);
+            }
+            return result;
+#else
+#if WINRT
+            Attribute[] all = System.Linq.Enumerable.ToArray(member.GetCustomAttributes(inherit));
+#else
+            object[] all = member.GetCustomAttributes(inherit);
+#endif
+            AttributeMap[] result = new AttributeMap[all.Length];
+            for(int i = 0 ; i < all.Length ; i++)
+            {
+                result[i] = new ReflectionAttributeMap((Attribute)all[i]);
+            }
+            return result;
+#endif
+        }
+        public static AttributeMap[] Create(TypeModel model, Assembly assembly)
+        {
+            
+#if FEAT_IKVM
+            const bool inherit = false;
+            System.Collections.Generic.IList<CustomAttributeData> all = assembly.__GetCustomAttributes(model.MapType(typeof(Attribute)), inherit);
+            AttributeMap[] result = new AttributeMap[all.Count];
+            int index = 0;
+            foreach (CustomAttributeData attrib in all)
+            {
+                result[index++] = new AttributeDataMap(attrib);
+            }
+            return result;
+#else
+#if WINRT
+            Attribute[] all = System.Linq.Enumerable.ToArray(assembly.GetCustomAttributes());
+#else
+            const bool inherit = false;
+            object[] all = assembly.GetCustomAttributes(inherit);
+#endif
+            AttributeMap[] result = new AttributeMap[all.Length];
+            for(int i = 0 ; i < all.Length ; i++)
+            {
+                result[i] = new ReflectionAttributeMap((Attribute)all[i]);
+            }
+            return result;
+#endif
+        }
+#if FEAT_IKVM
+        private sealed class AttributeDataMap : AttributeMap
+        {
+            public override Type AttributeType
+            {
+                get { return attribute.Constructor.DeclaringType; }
+            }
+            private readonly CustomAttributeData attribute;
+            public AttributeDataMap(CustomAttributeData attribute)
+            {
+                this.attribute = attribute;
+            }
+            public override bool TryGet(string key, bool publicOnly, out object value)
+            {
+                foreach (CustomAttributeNamedArgument arg in attribute.NamedArguments)
+                {
+                    if (string.Equals(arg.MemberInfo.Name, key, StringComparison.OrdinalIgnoreCase))
+                    {
+                        value = arg.TypedValue.Value;
+                        return true;
+                    }
+                }
+
+                    
+                int index = 0;
+                ParameterInfo[] parameters = attribute.Constructor.GetParameters();
+                foreach (CustomAttributeTypedArgument arg in attribute.ConstructorArguments)
+                {
+                    if (string.Equals(parameters[index++].Name, key, StringComparison.OrdinalIgnoreCase))
+                    {
+                        value = arg.Value;
+                        return true;
+                    }
+                }
+                value = null;
+                return false;
+            }
+        }
+#else
+        public abstract object Target { get; }
+        private sealed class ReflectionAttributeMap : AttributeMap
+        {
+            public override object Target
+            {
+                get { return attribute; }
+            }
+            public override Type AttributeType
+            {
+                get { return attribute.GetType(); }
+            }
+            public override bool TryGet(string key, bool publicOnly, out object value)
+            {
+                MemberInfo[] members = Helpers.GetInstanceFieldsAndProperties(attribute.GetType(), publicOnly);
+                foreach (MemberInfo member in members)
+                {
+#if FX11
+                    if (member.Name.ToUpper() == key.ToUpper())
+#else
+                    if (string.Equals(member.Name, key, StringComparison.OrdinalIgnoreCase))
+#endif
+                    {
+                        PropertyInfo prop = member as PropertyInfo;
+                        if (prop != null) {
+                            value = prop.GetValue(attribute, null);
+                            return true;
+                        }
+                        FieldInfo field = member as FieldInfo;
+                        if (field != null) {
+                            value = field.GetValue(attribute);
+                            return true;
+                        }
+
+                        throw new NotSupportedException(member.GetType().Name);
+                    }
+                }
+                value = null;
+                return false;
+            }
+            private readonly Attribute attribute;
+            public ReflectionAttributeMap(Attribute attribute)
+            {
+                this.attribute = attribute;
+            }
+        }
+#endif
+    }
+}
+#endif

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/Meta/AttributeMap.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 9d113bdb4bb5aa94fb27939b26628db3
+timeCreated: 1515899113
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 246 - 0
Unity/Assets/Plugins/protobuf-net/Meta/BasicList.cs

@@ -0,0 +1,246 @@
+using System;
+using System.Collections;
+
+namespace ProtoBuf.Meta
+{
+
+    internal sealed class MutableList : BasicList
+    {
+        /*  Like BasicList, but allows existing values to be changed
+         */ 
+        public new object this[int index] {
+            get { return head[index]; }
+            set { head[index] = value; }
+        }
+        public void RemoveLast()
+        {
+            head.RemoveLastWithMutate();
+        }
+
+        public void Clear()
+        {
+            head.Clear();
+        }
+    }
+    internal class BasicList : IEnumerable
+    {
+        /* Requirements:
+         *   - Fast access by index
+         *   - Immutable in the tail, so a node can be read (iterated) without locking
+         *   - Lock-free tail handling must match the memory mode; struct for Node
+         *     wouldn't work as "read" would not be atomic
+         *   - Only operation required is append, but this shouldn't go out of its
+         *     way to be inefficient
+         *   - Assume that the caller is handling thread-safety (to co-ordinate with
+         *     other code); no attempt to be thread-safe
+         *   - Assume that the data is private; internal data structure is allowed to
+         *     be mutable (i.e. array is fine as long as we don't screw it up)
+         */
+        private static readonly Node nil = new Node(null, 0);
+        public void CopyTo(Array array, int offset)
+        {
+            head.CopyTo(array, offset);
+        }
+        protected Node head = nil;
+        public int Add(object value)
+        {
+            return (head = head.Append(value)).Length - 1;
+        }
+        public object this[int index] { get { return head[index]; } }
+        //public object TryGet(int index)
+        //{
+        //    return head.TryGet(index);
+        //}
+        public void Trim() { head = head.Trim(); }
+        public int Count { get { return head.Length; } }
+        IEnumerator IEnumerable.GetEnumerator() { return new NodeEnumerator(head); }
+        public NodeEnumerator GetEnumerator() { return new NodeEnumerator(head); }
+
+        public struct NodeEnumerator : IEnumerator
+        {
+            private int position;
+            private readonly Node node;
+            internal NodeEnumerator(Node node)
+            {
+                this.position = -1;
+                this.node = node;
+            }
+            void IEnumerator.Reset() { position = -1; }
+            public object Current { get { return node[position]; } }
+            public bool MoveNext()
+            {
+                int len = node.Length;
+                return (position <= len) && (++position < len);
+            }
+        }
+        internal sealed class Node
+        {
+            public object this[int index]
+            {
+                get {
+                    if (index >= 0 && index < length)
+                    {
+                        return data[index];
+                    }
+                    throw new ArgumentOutOfRangeException("index");
+                }
+                set
+                {
+                    if (index >= 0 && index < length)
+                    {
+                        data[index] = value;
+                    }
+                    else
+                    {
+                        throw new ArgumentOutOfRangeException("index");
+                    }
+                }
+            }
+            //public object TryGet(int index)
+            //{
+            //    return (index >= 0 && index < length) ? data[index] : null;
+            //}
+            private readonly object[] data;
+            
+            private int length;
+            public int Length { get { return length; } }
+            internal Node(object[] data, int length)
+            {
+                Helpers.DebugAssert((data == null && length == 0) ||
+                    (data != null && length > 0 && length <= data.Length));
+                this.data = data;
+
+                this.length = length;
+            }
+            public void RemoveLastWithMutate()
+            {
+                if (length == 0) throw new InvalidOperationException();
+                length -= 1;
+            }
+            public Node Append(object value)
+            {
+                object[] newData;
+                int newLength = length + 1;
+                if (data == null)
+                {
+                    newData = new object[10];
+                }
+                else if (length == data.Length)
+                {
+                    newData = new object[data.Length * 2];
+                    Array.Copy(data, newData, length);
+                } else
+                {
+                    newData = data;
+                }
+                newData[length] = value;
+                return new Node(newData, newLength);
+            }
+            public Node Trim()
+            {
+                if (length == 0 || length == data.Length) return this;
+                object[] newData = new object[length];
+                Array.Copy(data, newData, length);
+                return new Node(newData, length);
+            }
+
+            internal int IndexOfString(string value)
+            {
+                for (int i = 0; i < length; i++)
+                {
+                    if ((string)value == (string)data[i]) return i;
+                }
+                return -1;
+            }
+            internal int IndexOfReference(object instance)
+            {
+                for (int i = 0; i < length; i++)
+                {
+                    if ((object)instance == (object)data[i]) return i;
+                } // ^^^ (object) above should be preserved, even if this was typed; needs
+                  // to be a reference check
+                return -1;
+            }
+            internal int IndexOf(MatchPredicate predicate, object ctx)
+            {
+                for (int i = 0; i < length; i++)
+                {
+                    if (predicate(data[i], ctx)) return i;
+                }
+                return -1;
+            }
+
+            internal void CopyTo(Array array, int offset)
+            {
+                if (length > 0)
+                {
+                    Array.Copy(data, 0, array, offset, length);
+                }
+            }
+
+            internal void Clear()
+            {
+                if(data != null)
+                {
+                    Array.Clear(data, 0, data.Length);
+                }
+                length = 0;
+            }
+        }
+
+        internal int IndexOf(MatchPredicate predicate, object ctx)
+        {
+            return head.IndexOf(predicate, ctx);
+        }
+        internal int IndexOfString(string value)
+        {
+            return head.IndexOfString(value);
+        }
+        internal int IndexOfReference(object instance)
+        {
+            return head.IndexOfReference(instance);
+        }
+
+        internal delegate bool MatchPredicate(object value, object ctx);
+
+        internal bool Contains(object value)
+        {
+            foreach (object obj in this)
+            {
+                if (object.Equals(obj, value)) return true;
+            }
+            return false;
+        }
+        internal sealed class Group
+        {
+            public readonly int First;
+            public readonly BasicList Items;
+            public Group(int first)
+            {
+                this.First = first;
+                this.Items = new BasicList();
+            }
+        }
+        internal static BasicList GetContiguousGroups(int[] keys, object[] values)
+        {
+            if (keys == null) throw new ArgumentNullException("keys");
+            if (values == null) throw new ArgumentNullException("values");
+            if (values.Length < keys.Length) throw new ArgumentException("Not all keys are covered by values", "values");
+            BasicList outer = new BasicList();
+            Group group = null;
+            for (int i = 0; i < keys.Length; i++)
+            {
+                if (i == 0 || keys[i] != keys[i - 1]) { group = null; }
+                if (group == null)
+                {
+                    group = new Group(keys[i]);
+                    outer.Add(group);
+                }
+                group.Items.Add(values[i]);
+            }
+            return outer;
+        }
+    }
+
+
+}

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/Meta/BasicList.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 29a4c7082e074e34ca71d6dd7fde3eb9
+timeCreated: 1515899112
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 107 - 0
Unity/Assets/Plugins/protobuf-net/Meta/CallbackSet.cs

@@ -0,0 +1,107 @@
+#if !NO_RUNTIME
+using System;
+
+#if FEAT_IKVM
+using Type = IKVM.Reflection.Type;
+using IKVM.Reflection;
+#else
+using System.Reflection;
+#endif
+
+namespace ProtoBuf.Meta
+{
+    /// <summary>
+    /// Represents the set of serialization callbacks to be used when serializing/deserializing a type.
+    /// </summary>
+    public class CallbackSet
+    {
+        private readonly MetaType metaType;
+        internal CallbackSet(MetaType metaType)
+        {
+            if (metaType == null) throw new ArgumentNullException("metaType");
+            this.metaType = metaType;
+        }
+        internal MethodInfo this[TypeModel.CallbackType callbackType]
+        {
+            get
+            {
+                switch (callbackType)
+                {
+                    case TypeModel.CallbackType.BeforeSerialize: return beforeSerialize;
+                    case TypeModel.CallbackType.AfterSerialize: return afterSerialize;
+                    case TypeModel.CallbackType.BeforeDeserialize: return beforeDeserialize;
+                    case TypeModel.CallbackType.AfterDeserialize: return afterDeserialize;
+                    default: throw new ArgumentException("Callback type not supported: " + callbackType.ToString(), "callbackType");
+                }
+            }
+        }
+        internal static bool CheckCallbackParameters(TypeModel model, MethodInfo method)
+        {
+            ParameterInfo[] args = method.GetParameters();
+            for (int i = 0; i < args.Length; i++)
+            {
+                Type paramType = args[i].ParameterType;
+                if(paramType == model.MapType(typeof(SerializationContext))) {}
+                else if(paramType == model.MapType(typeof(System.Type))) {}
+#if PLAT_BINARYFORMATTER
+                else if(paramType == model.MapType(typeof(System.Runtime.Serialization.StreamingContext))) {}
+#endif
+                else return false;
+            }
+            return true;
+        }
+        private MethodInfo SanityCheckCallback(TypeModel model, MethodInfo callback)
+        {
+            metaType.ThrowIfFrozen();
+            if (callback == null) return callback; // fine
+            if (callback.IsStatic) throw new ArgumentException("Callbacks cannot be static", "callback");
+            if (callback.ReturnType != model.MapType(typeof(void))
+                || !CheckCallbackParameters(model, callback))
+            {
+                throw CreateInvalidCallbackSignature(callback);
+            }
+            return callback;
+        }
+        internal static Exception CreateInvalidCallbackSignature(MethodInfo method)
+        {
+            return new NotSupportedException("Invalid callback signature in " + method.DeclaringType.FullName + "." + method.Name);
+        }
+        private MethodInfo beforeSerialize, afterSerialize, beforeDeserialize, afterDeserialize;
+        /// <summary>Called before serializing an instance</summary>
+        public MethodInfo BeforeSerialize
+        {
+            get { return beforeSerialize; }
+            set { beforeSerialize = SanityCheckCallback(metaType.Model, value); }
+        }
+        /// <summary>Called before deserializing an instance</summary>
+        public MethodInfo BeforeDeserialize
+        {
+            get { return beforeDeserialize; }
+            set { beforeDeserialize = SanityCheckCallback(metaType.Model, value); }
+        }
+        /// <summary>Called after serializing an instance</summary>
+        public MethodInfo AfterSerialize
+        {
+            get { return afterSerialize; }
+            set { afterSerialize = SanityCheckCallback(metaType.Model, value); }
+        }
+        /// <summary>Called after deserializing an instance</summary>
+        public MethodInfo AfterDeserialize
+        {
+            get { return afterDeserialize; }
+            set { afterDeserialize = SanityCheckCallback(metaType.Model, value); }
+        }
+        /// <summary>
+        /// True if any callback is set, else False
+        /// </summary>
+        public bool NonTrivial
+        {
+            get
+            {
+                return beforeSerialize != null || beforeDeserialize != null
+                    || afterSerialize != null || afterDeserialize != null;
+            }
+        }
+    }
+}
+#endif

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/Meta/CallbackSet.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 0e13df364e5504540a1a196b64da7a48
+timeCreated: 1515899112
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 1858 - 0
Unity/Assets/Plugins/protobuf-net/Meta/MetaType.cs

@@ -0,0 +1,1858 @@
+#if !NO_RUNTIME
+using System;
+using System.Collections;
+using System.Text;
+using ProtoBuf.Serializers;
+
+
+#if FEAT_IKVM
+using Type = IKVM.Reflection.Type;
+using IKVM.Reflection;
+#if FEAT_COMPILER
+using IKVM.Reflection.Emit;
+#endif
+#else
+using System.Reflection;
+#if FEAT_COMPILER
+using System.Reflection.Emit;
+#endif
+#endif
+
+
+namespace ProtoBuf.Meta
+{
+    /// <summary>
+    /// Represents a type at runtime for use with protobuf, allowing the field mappings (etc) to be defined
+    /// </summary>
+    public class MetaType : ISerializerProxy
+    {
+        internal sealed class Comparer : IComparer
+#if !NO_GENERICS
+             , System.Collections.Generic.IComparer<MetaType>
+#endif
+        {
+            public static readonly Comparer Default = new Comparer();
+            public int Compare(object x, object y)
+            {
+                return Compare(x as MetaType, y as MetaType);
+            }
+            public int Compare(MetaType x, MetaType y)
+            {
+                if (ReferenceEquals(x, y)) return 0;
+                if (x == null) return -1;
+                if (y == null) return 1;
+
+#if FX11
+                return string.Compare(x.GetSchemaTypeName(), y.GetSchemaTypeName());
+#else
+                return string.Compare(x.GetSchemaTypeName(), y.GetSchemaTypeName(), StringComparison.Ordinal);
+#endif
+            }
+        }
+        /// <summary>
+        /// Get the name of the type being represented
+        /// </summary>
+        public override string ToString()
+        {
+            return type.ToString();
+        }
+        IProtoSerializer ISerializerProxy.Serializer { get { return Serializer; } }
+        private MetaType baseType;
+        /// <summary>
+        /// Gets the base-type for this type
+        /// </summary>
+        public MetaType BaseType {
+            get { return baseType; }
+        }
+        internal TypeModel Model { get { return model; } }
+
+        /// <summary>
+        /// When used to compile a model, should public serialization/deserialzation methods
+        /// be included for this type?
+        /// </summary>
+        public bool IncludeSerializerMethod
+        {   // negated to minimize common-case / initializer
+            get { return !HasFlag(OPTIONS_PrivateOnApi); }
+            set { SetFlag(OPTIONS_PrivateOnApi, !value, true); }
+        }
+
+        /// <summary>
+        /// Should this type be treated as a reference by default?
+        /// </summary>
+        public bool AsReferenceDefault
+        { 
+            get { return HasFlag(OPTIONS_AsReferenceDefault); }
+            set { SetFlag(OPTIONS_AsReferenceDefault, value, true); }
+        }
+
+        private BasicList subTypes;
+        private bool IsValidSubType(Type subType)
+        {
+#if WINRT
+            return typeInfo.IsAssignableFrom(subType.GetTypeInfo());
+#else
+            return type.IsAssignableFrom(subType);
+#endif
+        }
+        /// <summary>
+        /// Adds a known sub-type to the inheritance model
+        /// </summary>
+        public MetaType AddSubType(int fieldNumber, Type derivedType)
+        {
+            return AddSubType(fieldNumber, derivedType, DataFormat.Default);
+        }
+        /// <summary>
+        /// Adds a known sub-type to the inheritance model
+        /// </summary>
+        public MetaType AddSubType(int fieldNumber, Type derivedType, DataFormat dataFormat)
+        {
+            if (derivedType == null) throw new ArgumentNullException("derivedType");
+            if (fieldNumber < 1) throw new ArgumentOutOfRangeException("fieldNumber");
+#if WINRT
+            if (!(typeInfo.IsClass || typeInfo.IsInterface) || typeInfo.IsSealed) {
+#else
+            if (!(type.IsClass || type.IsInterface) || type.IsSealed) {
+#endif
+                throw new InvalidOperationException("Sub-types can only be added to non-sealed classes");
+            }
+            if (!IsValidSubType(derivedType))
+            {
+                throw new ArgumentException(derivedType.Name + " is not a valid sub-type of " + type.Name, "derivedType");
+            }
+            MetaType derivedMeta = model[derivedType];
+            ThrowIfFrozen();
+            derivedMeta.ThrowIfFrozen();
+            SubType subType = new SubType(fieldNumber, derivedMeta, dataFormat);
+            ThrowIfFrozen();
+
+            derivedMeta.SetBaseType(this); // includes ThrowIfFrozen
+            if (subTypes == null) subTypes = new BasicList();
+            subTypes.Add(subType);
+            return this;
+        }
+#if WINRT
+        internal static readonly TypeInfo ienumerable = typeof(IEnumerable).GetTypeInfo();
+#else
+        internal static readonly System.Type ienumerable = typeof(IEnumerable);
+#endif
+        private void SetBaseType(MetaType baseType)
+        {
+            if (baseType == null) throw new ArgumentNullException("baseType");
+            if (this.baseType == baseType) return;
+            if (this.baseType != null) throw new InvalidOperationException("A type can only participate in one inheritance hierarchy");
+
+            MetaType type = baseType;
+            while (type != null)
+            {
+                if (ReferenceEquals(type, this)) throw new InvalidOperationException("Cyclic inheritance is not allowed");
+                type = type.baseType;
+            }
+            this.baseType = baseType;
+        }
+
+        private CallbackSet callbacks;
+        /// <summary>
+        /// Indicates whether the current type has defined callbacks 
+        /// </summary>
+        public bool HasCallbacks
+        {
+            get { return callbacks != null && callbacks.NonTrivial; }
+        }
+
+        /// <summary>
+        /// Indicates whether the current type has defined subtypes
+        /// </summary>
+        public bool HasSubtypes
+        {
+            get { return subTypes != null && subTypes.Count != 0; }
+        }
+
+        /// <summary>
+        /// Returns the set of callbacks defined for this type
+        /// </summary>
+        public CallbackSet Callbacks
+        {
+            get
+            {
+                if (callbacks == null) callbacks = new CallbackSet(this);
+                return callbacks;
+            }
+        }
+
+        private bool IsValueType
+        {
+            get
+            {
+#if WINRT
+                return typeInfo.IsValueType;
+#else
+                return type.IsValueType;
+#endif
+            }
+        }
+        /// <summary>
+        /// Assigns the callbacks to use during serialiation/deserialization.
+        /// </summary>
+        /// <param name="beforeSerialize">The method (or null) called before serialization begins.</param>
+        /// <param name="afterSerialize">The method (or null) called when serialization is complete.</param>
+        /// <param name="beforeDeserialize">The method (or null) called before deserialization begins (or when a new instance is created during deserialization).</param>
+        /// <param name="afterDeserialize">The method (or null) called when deserialization is complete.</param>
+        /// <returns>The set of callbacks.</returns>
+        public MetaType SetCallbacks(MethodInfo beforeSerialize, MethodInfo afterSerialize, MethodInfo beforeDeserialize, MethodInfo afterDeserialize)
+        {
+            CallbackSet callbacks = Callbacks;
+            callbacks.BeforeSerialize = beforeSerialize;
+            callbacks.AfterSerialize = afterSerialize;
+            callbacks.BeforeDeserialize = beforeDeserialize;
+            callbacks.AfterDeserialize = afterDeserialize;
+            return this;
+        }
+        /// <summary>
+        /// Assigns the callbacks to use during serialiation/deserialization.
+        /// </summary>
+        /// <param name="beforeSerialize">The name of the method (or null) called before serialization begins.</param>
+        /// <param name="afterSerialize">The name of the method (or null) called when serialization is complete.</param>
+        /// <param name="beforeDeserialize">The name of the method (or null) called before deserialization begins (or when a new instance is created during deserialization).</param>
+        /// <param name="afterDeserialize">The name of the method (or null) called when deserialization is complete.</param>
+        /// <returns>The set of callbacks.</returns>
+        public MetaType SetCallbacks(string beforeSerialize, string afterSerialize, string beforeDeserialize, string afterDeserialize)
+        {
+            if (IsValueType) throw new InvalidOperationException();
+            CallbackSet callbacks = Callbacks;
+            callbacks.BeforeSerialize = ResolveMethod(beforeSerialize, true);
+            callbacks.AfterSerialize = ResolveMethod(afterSerialize, true);
+            callbacks.BeforeDeserialize = ResolveMethod(beforeDeserialize, true);
+            callbacks.AfterDeserialize = ResolveMethod(afterDeserialize, true);
+            return this;
+        }
+
+        internal string GetSchemaTypeName()
+        {
+            if (surrogate != null) return model[surrogate].GetSchemaTypeName();
+
+            if (!Helpers.IsNullOrEmpty(name)) return name;
+
+            string typeName = type.Name;
+#if !NO_GENERICS
+            if (type
+#if WINRT
+                .GetTypeInfo()
+#endif       
+                .IsGenericType)
+            {
+                StringBuilder sb = new StringBuilder(typeName);
+                int split = typeName.IndexOf('`');
+                if (split >= 0) sb.Length = split;
+                foreach (Type arg in type
+#if WINRT
+                    .GetTypeInfo().GenericTypeArguments
+#else               
+                    .GetGenericArguments()
+#endif
+                    )
+                {
+                    sb.Append('_');
+                    Type tmp = arg;
+                    int key = model.GetKey(ref tmp);
+                    MetaType mt;
+                    if (key >= 0 && (mt = model[tmp]) != null && mt.surrogate == null) // <=== need to exclude surrogate to avoid chance of infinite loop
+                    {
+                        
+                        sb.Append(mt.GetSchemaTypeName());
+                    }
+                    else
+                    {
+                        sb.Append(tmp.Name);
+                    }
+                }
+                return sb.ToString();
+            }
+#endif
+            return typeName;
+        }
+
+        private string name;
+        /// <summary>
+        /// Gets or sets the name of this contract.
+        /// </summary>
+        public string Name
+        {
+            get
+            {
+                return name;
+            }
+            set
+            {
+                ThrowIfFrozen();
+                name = value;
+            }
+        }
+
+        private MethodInfo factory;
+        /// <summary>
+        /// Designate a factory-method to use to create instances of this type
+        /// </summary>
+        public MetaType SetFactory(MethodInfo factory)
+        {
+            model.VerifyFactory(factory, type);
+            ThrowIfFrozen();
+            this.factory = factory;
+            return this;
+        }
+
+
+
+        /// <summary>
+        /// Designate a factory-method to use to create instances of this type
+        /// </summary>
+        public MetaType SetFactory(string factory)
+        {
+            return SetFactory(ResolveMethod(factory, false));
+        }
+
+        private MethodInfo ResolveMethod(string name, bool instance)
+        {
+            if (Helpers.IsNullOrEmpty(name)) return null;
+#if WINRT
+            return instance ? Helpers.GetInstanceMethod(typeInfo, name) : Helpers.GetStaticMethod(typeInfo, name);
+#else
+            return instance ? Helpers.GetInstanceMethod(type, name) : Helpers.GetStaticMethod(type, name);
+#endif
+        }
+        private readonly RuntimeTypeModel model;
+        internal static Exception InbuiltType(Type type)
+        {
+            return new ArgumentException("Data of this type has inbuilt behaviour, and cannot be added to a model in this way: " + type.FullName);
+        }
+        internal MetaType(RuntimeTypeModel model, Type type, MethodInfo factory)
+        {
+            this.factory = factory;
+            if (model == null) throw new ArgumentNullException("model");
+            if (type == null) throw new ArgumentNullException("type");
+            
+            IProtoSerializer coreSerializer = model.TryGetBasicTypeSerializer(type);
+            if (coreSerializer != null)
+            {
+                throw InbuiltType(type);
+            }
+            
+            this.type = type;
+#if WINRT
+            this.typeInfo = type.GetTypeInfo();
+#endif
+            this.model = model;
+            
+            if (Helpers.IsEnum(type))
+            {
+#if WINRT
+                EnumPassthru = typeInfo.IsDefined(typeof(FlagsAttribute), false);
+#else
+                EnumPassthru = type.IsDefined(model.MapType(typeof(FlagsAttribute)), false);
+#endif
+            }
+        }
+#if WINRT
+        private readonly TypeInfo typeInfo;
+#endif
+        /// <summary>
+        /// Throws an exception if the type has been made immutable
+        /// </summary>
+        protected internal void ThrowIfFrozen()
+        {
+            if ((flags & OPTIONS_Frozen)!=0) throw new InvalidOperationException("The type cannot be changed once a serializer has been generated for " + type.FullName);
+        }
+        //internal void Freeze() { flags |= OPTIONS_Frozen; }
+
+        private readonly Type type;
+        /// <summary>
+        /// The runtime type that the meta-type represents
+        /// </summary>
+        public Type Type { get { return type; } }
+        private IProtoTypeSerializer serializer;
+        internal IProtoTypeSerializer Serializer {
+            get {
+                if (serializer == null)
+                {
+                    int opaqueToken = 0;
+                    try
+                    {
+                        model.TakeLock(ref opaqueToken);
+                        if (serializer == null)
+                        { // double-check, but our main purpse with this lock is to ensure thread-safety with
+                            // serializers needing to wait until another thread has finished adding the properties
+                            SetFlag(OPTIONS_Frozen, true, false);
+                            serializer = BuildSerializer();
+#if FEAT_COMPILER && !FX11
+                            if (model.AutoCompile) CompileInPlace();
+#endif
+                        }
+                    }
+                    finally
+                    {
+                        model.ReleaseLock(opaqueToken);
+                    }
+                }
+                return serializer;
+            }
+        }
+        internal bool IsList
+        {
+            get
+            {
+                Type itemType = IgnoreListHandling ? null : TypeModel.GetListItemType(model, type);
+                return itemType != null;
+            }
+        }
+        private IProtoTypeSerializer BuildSerializer()
+        {
+            if (Helpers.IsEnum(type))
+            {
+                return new TagDecorator(ProtoBuf.Serializer.ListItemTag, WireType.Variant, false, new EnumSerializer(type, GetEnumMap()));
+            }
+            Type itemType = IgnoreListHandling ? null : TypeModel.GetListItemType(model, type);
+            if (itemType != null)
+            {
+                if(surrogate != null)
+                {
+                    throw new ArgumentException("Repeated data (a list, collection, etc) has inbuilt behaviour and cannot use a surrogate");
+                }
+                if(subTypes != null && subTypes.Count != 0)
+                {
+                    throw new ArgumentException("Repeated data (a list, collection, etc) has inbuilt behaviour and cannot be subclassed");
+                }
+                Type defaultType = null;
+                ResolveListTypes(model, type, ref itemType, ref defaultType);
+                ValueMember fakeMember = new ValueMember(model, ProtoBuf.Serializer.ListItemTag, type, itemType, defaultType, DataFormat.Default);
+                return new TypeSerializer(model, type, new int[] { ProtoBuf.Serializer.ListItemTag }, new IProtoSerializer[] { fakeMember.Serializer }, null, true, true, null, constructType, factory);
+            }
+            if (surrogate != null)
+            {
+                MetaType mt = model[surrogate], mtBase;
+                while ((mtBase = mt.baseType) != null) { mt = mtBase; }
+                return new SurrogateSerializer(model, type, surrogate, mt.Serializer);
+            }
+            if (IsAutoTuple)
+            {
+                MemberInfo[] mapping;
+                ConstructorInfo ctor = ResolveTupleConstructor(type, out mapping);
+                if(ctor == null) throw new InvalidOperationException();
+                return new TupleSerializer(model, ctor, mapping);
+            }
+            
+
+            fields.Trim();
+            int fieldCount = fields.Count;
+            int subTypeCount = subTypes == null ? 0 : subTypes.Count;
+            int[] fieldNumbers = new int[fieldCount + subTypeCount];
+            IProtoSerializer[] serializers = new IProtoSerializer[fieldCount + subTypeCount];
+            int i = 0;
+            if (subTypeCount != 0)
+            {
+                foreach (SubType subType in subTypes)
+                {
+#if WINRT
+                    if (!subType.DerivedType.IgnoreListHandling && ienumerable.IsAssignableFrom(subType.DerivedType.Type.GetTypeInfo()))
+#else
+                    if (!subType.DerivedType.IgnoreListHandling && model.MapType(ienumerable).IsAssignableFrom(subType.DerivedType.Type))
+#endif
+                    {
+                        throw new ArgumentException("Repeated data (a list, collection, etc) has inbuilt behaviour and cannot be used as a subclass");
+                    }
+                    fieldNumbers[i] = subType.FieldNumber;
+                    serializers[i++] = subType.Serializer;
+                }
+            }
+            if (fieldCount != 0)
+            {
+                foreach (ValueMember member in fields)
+                {
+                    fieldNumbers[i] = member.FieldNumber;
+                    serializers[i++] = member.Serializer;
+                }
+            }
+
+            BasicList baseCtorCallbacks = null;
+            MetaType tmp = BaseType;
+            
+            while (tmp != null)
+            {
+                MethodInfo method = tmp.HasCallbacks ? tmp.Callbacks.BeforeDeserialize : null;
+                if (method != null)
+                {
+                    if (baseCtorCallbacks == null) baseCtorCallbacks = new BasicList();
+                    baseCtorCallbacks.Add(method);
+                }
+                tmp = tmp.BaseType;
+            }
+            MethodInfo[] arr = null;
+            if (baseCtorCallbacks != null)
+            {
+                arr = new MethodInfo[baseCtorCallbacks.Count];
+                baseCtorCallbacks.CopyTo(arr, 0);
+                Array.Reverse(arr);
+            }
+            return new TypeSerializer(model, type, fieldNumbers, serializers, arr, baseType == null, UseConstructor, callbacks, constructType, factory);
+        }
+
+        [Flags]
+        internal enum AttributeFamily
+        {
+            None = 0, ProtoBuf = 1, DataContractSerialier = 2, XmlSerializer = 4, AutoTuple = 8
+        }
+        static Type GetBaseType(MetaType type)
+        {
+#if WINRT
+            return type.typeInfo.BaseType;
+#else
+            return type.type.BaseType;
+#endif
+        }
+        internal static bool GetAsReferenceDefault(RuntimeTypeModel model, Type type)
+        {
+            if (type == null) throw new ArgumentNullException("type");
+            if (Helpers.IsEnum(type)) return false; // never as-ref
+            AttributeMap[] typeAttribs = AttributeMap.Create(model, type, false);
+            for (int i = 0; i < typeAttribs.Length; i++)
+            {
+                if (typeAttribs[i].AttributeType.FullName == "ProtoBuf.ProtoContractAttribute")
+                {
+                    object tmp;
+                    if (typeAttribs[i].TryGet("AsReferenceDefault", out tmp)) return (bool)tmp;
+                }
+            }
+            return false;
+        }
+        internal void ApplyDefaultBehaviour()
+        {
+            Type baseType = GetBaseType(this);
+            if (baseType != null && model.FindWithoutAdd(baseType) == null
+                && GetContractFamily(model, baseType, null) != MetaType.AttributeFamily.None)
+            {
+                model.FindOrAddAuto(baseType, true, false, false);
+            }
+
+            AttributeMap[] typeAttribs = AttributeMap.Create(model, type, false);
+            AttributeFamily family = GetContractFamily(model, type, typeAttribs);
+            if(family == AttributeFamily.AutoTuple)
+            {
+                SetFlag(OPTIONS_AutoTuple, true, true);
+            }
+            bool isEnum = !EnumPassthru && Helpers.IsEnum(type);
+            if(family ==  AttributeFamily.None && !isEnum) return; // and you'd like me to do what, exactly?
+            BasicList partialIgnores = null, partialMembers = null;
+            int dataMemberOffset = 0, implicitFirstTag = 1;
+            bool inferTagByName = model.InferTagFromNameDefault;
+            ImplicitFields implicitMode = ImplicitFields.None;
+            string name = null;
+            for (int i = 0; i < typeAttribs.Length; i++)
+            {
+                AttributeMap item = (AttributeMap)typeAttribs[i];
+                object tmp;
+                string fullAttributeTypeName = item.AttributeType.FullName;
+                if (!isEnum && fullAttributeTypeName == "ProtoBuf.ProtoIncludeAttribute")
+                {
+                    int tag = 0;
+                    if (item.TryGet("tag", out tmp)) tag = (int)tmp;
+                    DataFormat dataFormat = DataFormat.Default;
+                    if(item.TryGet("DataFormat", out tmp))
+                    {
+                        dataFormat = (DataFormat)(int) tmp;
+                    }
+                    Type knownType = null;
+                    try
+                    {
+                        if (item.TryGet("knownTypeName", out tmp)) knownType = model.GetType((string)tmp, type
+#if WINRT
+                            .GetTypeInfo()
+#endif       
+                            .Assembly);
+                        else if (item.TryGet("knownType", out tmp)) knownType = (Type)tmp;
+                    }
+                    catch (Exception ex)
+                    {
+                        throw new InvalidOperationException("Unable to resolve sub-type of: " + type.FullName, ex);
+                    }
+                    if (knownType == null)
+                    {
+                        throw new InvalidOperationException("Unable to resolve sub-type of: " + type.FullName);
+                    }
+                    if(IsValidSubType(knownType)) AddSubType(tag, knownType, dataFormat);
+                }
+
+                if (fullAttributeTypeName == "ProtoBuf.ProtoPartialIgnoreAttribute")
+                {
+                    if (item.TryGet("MemberName", out tmp) && tmp != null)
+                    {
+                        if (partialIgnores == null) partialIgnores = new BasicList();
+                        partialIgnores.Add((string)tmp);
+                    }
+                }
+                if (!isEnum && fullAttributeTypeName == "ProtoBuf.ProtoPartialMemberAttribute")
+                {
+                    if (partialMembers == null) partialMembers = new BasicList();
+                    partialMembers.Add(item);
+                }
+
+                if (fullAttributeTypeName == "ProtoBuf.ProtoContractAttribute")
+                {
+                    if (item.TryGet("Name", out tmp)) name = (string) tmp;
+                    if (Helpers.IsEnum(type)) // note this is subtly different to isEnum; want to do this even if [Flags]
+                    {
+#if !FEAT_IKVM
+                        // IKVM can't access EnumPassthruHasValue, but conveniently, InferTagFromName will only be returned if set via ctor or property
+                        if (item.TryGet("EnumPassthruHasValue", false, out tmp) && (bool)tmp)
+#endif
+                        {
+                            if (item.TryGet("EnumPassthru", out tmp))
+                            {
+                                EnumPassthru = (bool)tmp;
+                                if (EnumPassthru) isEnum = false; // no longer treated as an enum
+                            }
+                        }
+                    }
+                    else
+                    {
+                        if (item.TryGet("DataMemberOffset", out tmp)) dataMemberOffset = (int) tmp;
+
+#if !FEAT_IKVM
+                        // IKVM can't access InferTagFromNameHasValue, but conveniently, InferTagFromName will only be returned if set via ctor or property
+                        if (item.TryGet("InferTagFromNameHasValue", false, out tmp) && (bool) tmp)
+#endif
+                        {
+                            if (item.TryGet("InferTagFromName", out tmp)) inferTagByName = (bool) tmp;
+                        }
+
+                        if (item.TryGet("ImplicitFields", out tmp) && tmp != null)
+                        {
+                            implicitMode = (ImplicitFields) (int) tmp; // note that this uses the bizarre unboxing rules of enums/underlying-types
+                        }
+
+                        if (item.TryGet("SkipConstructor", out tmp)) UseConstructor = !(bool) tmp;
+                        if (item.TryGet("IgnoreListHandling", out tmp)) IgnoreListHandling = (bool) tmp;
+                        if (item.TryGet("AsReferenceDefault", out tmp)) AsReferenceDefault = (bool) tmp;
+                        if (item.TryGet("ImplicitFirstTag", out tmp) && (int) tmp > 0) implicitFirstTag = (int) tmp;
+                    }
+                }
+
+                if (fullAttributeTypeName == "System.Runtime.Serialization.DataContractAttribute")
+                {
+                    if (name == null && item.TryGet("Name", out tmp)) name = (string)tmp;
+                }
+                if (fullAttributeTypeName == "System.Xml.Serialization.XmlTypeAttribute")
+                {
+                    if (name == null && item.TryGet("TypeName", out tmp)) name = (string)tmp;
+                }
+            }
+            if (!Helpers.IsNullOrEmpty(name)) Name = name;
+            if (implicitMode != ImplicitFields.None)
+            {
+                family &= AttributeFamily.ProtoBuf; // with implicit fields, **only** proto attributes are important
+            }
+            MethodInfo[] callbacks = null;
+
+            BasicList members = new BasicList();
+
+#if WINRT
+            System.Collections.Generic.IEnumerable<MemberInfo> foundList;
+            if(isEnum) {
+                foundList = type.GetRuntimeFields();
+            }
+            else
+            {
+                System.Collections.Generic.List<MemberInfo> list = new System.Collections.Generic.List<MemberInfo>();
+                foreach(PropertyInfo prop in type.GetRuntimeProperties()) {
+                    MethodInfo getter = Helpers.GetGetMethod(prop, false, false);
+                    if(getter != null && !getter.IsStatic) list.Add(prop);
+                }
+                foreach(FieldInfo fld in type.GetRuntimeFields()) if(fld.IsPublic && !fld.IsStatic) list.Add(fld);
+                foreach(MethodInfo mthd in type.GetRuntimeMethods()) if(mthd.IsPublic && !mthd.IsStatic) list.Add(mthd);
+                foundList = list;
+            }
+#else
+            MemberInfo[] foundList = type.GetMembers(isEnum ? BindingFlags.Public | BindingFlags.Static
+                : BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
+#endif
+            foreach (MemberInfo member in foundList)
+            {
+                if (member.DeclaringType != type) continue;
+                if (member.IsDefined(model.MapType(typeof(ProtoIgnoreAttribute)), true)) continue;
+                if (partialIgnores != null && partialIgnores.Contains(member.Name)) continue;
+
+                bool forced = false, isPublic, isField;
+                Type effectiveType;
+
+                
+                PropertyInfo property;
+                FieldInfo field;
+                MethodInfo method;
+                if((property = member as PropertyInfo) != null)
+                {
+                    if (isEnum) continue; // wasn't expecting any props!
+
+                    effectiveType = property.PropertyType;
+                    isPublic = Helpers.GetGetMethod(property, false, false) != null;
+                    isField = false;
+                    ApplyDefaultBehaviour_AddMembers(model, family, isEnum, partialMembers, dataMemberOffset, inferTagByName, implicitMode, members, member, ref forced, isPublic, isField, ref effectiveType);
+                } else if ((field = member as FieldInfo) != null)
+                {
+                    effectiveType = field.FieldType;
+                    isPublic = field.IsPublic;
+                    isField = true;
+                    if (isEnum && !field.IsStatic)
+                    { // only care about static things on enums; WinRT has a __value instance field!
+                        continue;
+                    }
+                    ApplyDefaultBehaviour_AddMembers(model, family, isEnum, partialMembers, dataMemberOffset, inferTagByName, implicitMode, members, member, ref forced, isPublic, isField, ref effectiveType);
+                } else if ((method = member as MethodInfo) != null)
+                {
+                    if (isEnum) continue;
+                    AttributeMap[] memberAttribs = AttributeMap.Create(model, method, false);
+                    if (memberAttribs != null && memberAttribs.Length > 0)
+                    {
+                        CheckForCallback(method, memberAttribs, "ProtoBuf.ProtoBeforeSerializationAttribute", ref callbacks, 0);
+                        CheckForCallback(method, memberAttribs, "ProtoBuf.ProtoAfterSerializationAttribute", ref callbacks, 1);
+                        CheckForCallback(method, memberAttribs, "ProtoBuf.ProtoBeforeDeserializationAttribute", ref callbacks, 2);
+                        CheckForCallback(method, memberAttribs, "ProtoBuf.ProtoAfterDeserializationAttribute", ref callbacks, 3);
+                        CheckForCallback(method, memberAttribs, "System.Runtime.Serialization.OnSerializingAttribute", ref callbacks, 4);
+                        CheckForCallback(method, memberAttribs, "System.Runtime.Serialization.OnSerializedAttribute", ref callbacks, 5);
+                        CheckForCallback(method, memberAttribs, "System.Runtime.Serialization.OnDeserializingAttribute", ref callbacks, 6);
+                        CheckForCallback(method, memberAttribs, "System.Runtime.Serialization.OnDeserializedAttribute", ref callbacks, 7);
+                    }
+                }
+            }
+            ProtoMemberAttribute[] arr = new ProtoMemberAttribute[members.Count];
+            members.CopyTo(arr, 0);
+            
+            if (inferTagByName || implicitMode != ImplicitFields.None)
+            {
+                Array.Sort(arr);
+                int nextTag = implicitFirstTag;
+                foreach (ProtoMemberAttribute normalizedAttribute in arr)
+                {
+                    if (!normalizedAttribute.TagIsPinned) // if ProtoMember etc sets a tag, we'll trust it
+                    {
+                        normalizedAttribute.Rebase(nextTag++);
+                    }
+                }
+            }
+
+            foreach (ProtoMemberAttribute normalizedAttribute in arr)
+            {
+                ValueMember vm = ApplyDefaultBehaviour(isEnum, normalizedAttribute);
+                if (vm != null)
+                {
+                    Add(vm);
+                }
+            }
+
+            if (callbacks != null)
+            {
+                SetCallbacks(Coalesce(callbacks, 0, 4), Coalesce(callbacks, 1, 5),
+                    Coalesce(callbacks, 2, 6), Coalesce(callbacks, 3, 7));
+            }
+        }
+
+        private static void ApplyDefaultBehaviour_AddMembers(TypeModel model, AttributeFamily family, bool isEnum, BasicList partialMembers, int dataMemberOffset, bool inferTagByName, ImplicitFields implicitMode, BasicList members, MemberInfo member, ref bool forced, bool isPublic, bool isField, ref Type effectiveType)
+        {
+            switch (implicitMode)
+            {
+                case ImplicitFields.AllFields:
+                    if (isField) forced = true;
+                    break;
+                case ImplicitFields.AllPublic:
+                    if (isPublic) forced = true;
+                    break;
+            }
+
+            // we just don't like delegate types ;p
+#if WINRT
+            if (effectiveType.GetTypeInfo().IsSubclassOf(typeof(Delegate))) effectiveType = null;
+#else
+            if (effectiveType.IsSubclassOf(model.MapType(typeof(Delegate)))) effectiveType = null;
+#endif
+            if (effectiveType != null)
+            {
+                ProtoMemberAttribute normalizedAttribute = NormalizeProtoMember(model, member, family, forced, isEnum, partialMembers, dataMemberOffset, inferTagByName);
+                if (normalizedAttribute != null) members.Add(normalizedAttribute);
+            }
+        }
+
+
+        static MethodInfo Coalesce(MethodInfo[] arr, int x, int y)
+        {
+            MethodInfo mi = arr[x];
+            if (mi == null) mi = arr[y];
+            return mi;
+        }
+
+        internal static AttributeFamily GetContractFamily(RuntimeTypeModel model, Type type, AttributeMap[] attributes)
+        {
+            AttributeFamily family = AttributeFamily.None;
+
+            if (attributes == null) attributes = AttributeMap.Create(model, type, false);
+
+            for (int i = 0; i < attributes.Length; i++)
+            {
+                switch (attributes[i].AttributeType.FullName)
+                {
+                    case "ProtoBuf.ProtoContractAttribute":
+                        bool tmp = false;
+                        GetFieldBoolean(ref tmp, attributes[i], "UseProtoMembersOnly");
+                        if (tmp) return AttributeFamily.ProtoBuf;
+                        family |= AttributeFamily.ProtoBuf;
+                        break;
+                    case "System.Xml.Serialization.XmlTypeAttribute":
+                        if (!model.AutoAddProtoContractTypesOnly)
+                        {
+                            family |= AttributeFamily.XmlSerializer;
+                        }
+                        break;
+                    case "System.Runtime.Serialization.DataContractAttribute":
+                        if (!model.AutoAddProtoContractTypesOnly)
+                        {
+                            family |= AttributeFamily.DataContractSerialier;
+                        }
+                        break;
+                }
+            }
+            if(family == AttributeFamily.None)
+            { // check for obvious tuples
+                MemberInfo[] mapping;
+                if(ResolveTupleConstructor(type, out mapping) != null)
+                {
+                    family |= AttributeFamily.AutoTuple;
+                }
+            }
+            return family;
+        }
+        internal static ConstructorInfo ResolveTupleConstructor(Type type, out MemberInfo[] mappedMembers)
+        {
+            mappedMembers = null;
+            if(type == null) throw new ArgumentNullException("type");
+#if WINRT
+            TypeInfo typeInfo = type.GetTypeInfo();
+            if (typeInfo.IsAbstract) return null; // as if!
+            ConstructorInfo[] ctors = Helpers.GetConstructors(typeInfo, false);
+#else
+            if(type.IsAbstract) return null; // as if!
+            ConstructorInfo[] ctors = Helpers.GetConstructors(type, false);
+#endif
+            // need to have an interesting constructor to bother even checking this stuff
+            if(ctors.Length == 0 || (ctors.Length == 1 && ctors[0].GetParameters().Length == 0)) return null;
+
+            MemberInfo[] fieldsPropsUnfiltered = Helpers.GetInstanceFieldsAndProperties(type, true);
+            BasicList memberList = new BasicList();
+            for (int i = 0; i < fieldsPropsUnfiltered.Length; i++)
+            {
+                PropertyInfo prop = fieldsPropsUnfiltered[i] as PropertyInfo;
+                if (prop != null)
+                {
+                    if (!prop.CanRead) return null; // no use if can't read
+                    if (prop.CanWrite && Helpers.GetSetMethod(prop, false, false) != null) return null; // don't allow a public set (need to allow non-public to handle Mono's KeyValuePair<,>)
+                    memberList.Add(prop);
+                }
+                else
+                {
+                    FieldInfo field = fieldsPropsUnfiltered[i] as FieldInfo;
+                    if (field != null)
+                    {
+                        if (!field.IsInitOnly) return null; // all public fields must be readonly to be counted a tuple
+                        memberList.Add(field);
+                    }
+                }
+            }
+            if (memberList.Count == 0)
+            {
+                return null;
+            }
+
+            MemberInfo[] members = new MemberInfo[memberList.Count];
+            memberList.CopyTo(members, 0);
+
+            int[] mapping = new int[members.Length];
+            int found = 0;
+            ConstructorInfo result = null;
+            mappedMembers = new MemberInfo[mapping.Length];
+            for(int i = 0 ; i < ctors.Length ; i++)
+            {
+                ParameterInfo[] parameters = ctors[i].GetParameters();
+
+                if (parameters.Length != members.Length) continue;
+
+                // reset the mappings to test
+                for (int j = 0; j < mapping.Length; j++) mapping[j] = -1;
+
+                for(int j = 0 ; j < parameters.Length ; j++)
+                {
+                    string lower = parameters[j].Name.ToLower();
+                    for(int k = 0 ; k < members.Length ; k++)
+                    {
+                        if (members[k].Name.ToLower() != lower) continue;
+                        Type memberType = Helpers.GetMemberType(members[k]);
+                        if (memberType != parameters[j].ParameterType) continue;
+
+                        mapping[j] = k;
+                    }
+                }
+                // did we map all?
+                bool notMapped = false;
+                for (int j = 0; j < mapping.Length; j++)
+                {
+                    if (mapping[j] < 0)
+                    {
+                        notMapped = true;
+                        break;
+                    }
+                    mappedMembers[j] = members[mapping[j]];
+                }
+
+                if (notMapped) continue;
+                found++;
+                result = ctors[i];
+
+            }
+            return found == 1 ? result : null;
+        }
+        private static void CheckForCallback(MethodInfo method, AttributeMap[] attributes, string callbackTypeName, ref MethodInfo[] callbacks, int index)
+        {
+            for(int i = 0 ; i < attributes.Length ; i++)
+            {
+                if(attributes[i].AttributeType.FullName == callbackTypeName)
+                {
+                    if (callbacks == null) { callbacks = new MethodInfo[8]; }
+                    else if (callbacks[index] != null)
+                    {
+#if WINRT || FEAT_IKVM
+                        Type reflected = method.DeclaringType;
+#else
+                        Type reflected = method.ReflectedType;
+#endif
+                        throw new ProtoException("Duplicate " + callbackTypeName + " callbacks on " + reflected.FullName);
+                    }
+                    callbacks[index] = method;
+                }
+            }
+        }
+        private static bool HasFamily(AttributeFamily value, AttributeFamily required)
+        {
+            return (value & required) == required;
+        }
+        
+        private static ProtoMemberAttribute NormalizeProtoMember(TypeModel model, MemberInfo member, AttributeFamily family, bool forced, bool isEnum, BasicList partialMembers, int dataMemberOffset, bool inferByTagName)
+        {
+            if (member == null || (family == AttributeFamily.None && !isEnum)) return null; // nix
+            int fieldNumber = int.MinValue, minAcceptFieldNumber = inferByTagName ? -1 : 1;
+            string name = null;
+            bool isPacked = false, ignore = false, done = false, isRequired = false, asReference = false, asReferenceHasValue = false, dynamicType = false, tagIsPinned = false, overwriteList = false;
+            DataFormat dataFormat = DataFormat.Default;
+            if (isEnum) forced = true;
+            AttributeMap[] attribs = AttributeMap.Create(model, member, true);
+            AttributeMap attrib;
+
+            if (isEnum)
+            {
+                attrib = GetAttribute(attribs, "ProtoBuf.ProtoIgnoreAttribute");
+                if (attrib != null)
+                {
+                    ignore = true;
+                }
+                else
+                {
+                    attrib = GetAttribute(attribs, "ProtoBuf.ProtoEnumAttribute");
+#if WINRT || PORTABLE || CF || FX11
+                    fieldNumber = Convert.ToInt32(((FieldInfo)member).GetValue(null));
+#else
+                    fieldNumber = Convert.ToInt32(((FieldInfo)member).GetRawConstantValue());
+#endif
+                    if (attrib != null)
+                    {
+                        GetFieldName(ref name, attrib, "Name");
+#if !FEAT_IKVM // IKVM can't access HasValue, but conveniently, Value will only be returned if set via ctor or property
+                        if ((bool)Helpers.GetInstanceMethod(attrib.AttributeType
+#if WINRT
+                             .GetTypeInfo()
+#endif
+                            ,"HasValue").Invoke(attrib.Target, null))
+#endif
+                        {
+                            object tmp;
+                            if(attrib.TryGet("Value", out tmp)) fieldNumber = (int)tmp;
+                        }
+                    }
+
+                }
+                done = true;
+            }
+
+            if (!ignore && !done) // always consider ProtoMember 
+            {
+                attrib = GetAttribute(attribs, "ProtoBuf.ProtoMemberAttribute");
+                GetIgnore(ref ignore, attrib, attribs, "ProtoBuf.ProtoIgnoreAttribute");
+
+                if (!ignore && attrib != null)
+                {
+                    GetFieldNumber(ref fieldNumber, attrib, "Tag");
+                    GetFieldName(ref name, attrib, "Name");
+                    GetFieldBoolean(ref isRequired, attrib, "IsRequired");
+                    GetFieldBoolean(ref isPacked, attrib, "IsPacked");
+                    GetFieldBoolean(ref overwriteList, attrib, "OverwriteList");
+                    GetDataFormat(ref dataFormat, attrib, "DataFormat");
+
+#if !FEAT_IKVM
+                    // IKVM can't access AsReferenceHasValue, but conveniently, AsReference will only be returned if set via ctor or property
+                    GetFieldBoolean(ref asReferenceHasValue, attrib, "AsReferenceHasValue", false);
+                    if(asReferenceHasValue)
+#endif
+                    {
+                        asReferenceHasValue = GetFieldBoolean(ref asReference, attrib, "AsReference", true);
+                    }
+                    GetFieldBoolean(ref dynamicType, attrib, "DynamicType");
+                    done = tagIsPinned = fieldNumber > 0; // note minAcceptFieldNumber only applies to non-proto
+                }
+
+                if (!done && partialMembers != null)
+                {
+                    foreach (AttributeMap ppma in partialMembers)
+                    {
+                        object tmp;
+                        if(ppma.TryGet("MemberName", out tmp) && (string)tmp == member.Name)
+                        {
+                            GetFieldNumber(ref fieldNumber, ppma, "Tag");
+                            GetFieldName(ref name, ppma, "Name");
+                            GetFieldBoolean(ref isRequired, ppma, "IsRequired");
+                            GetFieldBoolean(ref isPacked, ppma, "IsPacked");
+                            GetFieldBoolean(ref overwriteList, attrib, "OverwriteList");
+                            GetDataFormat(ref dataFormat, ppma, "DataFormat");
+
+#if !FEAT_IKVM
+                            // IKVM can't access AsReferenceHasValue, but conveniently, AsReference will only be returned if set via ctor or property
+                            GetFieldBoolean(ref asReferenceHasValue, attrib, "AsReferenceHasValue", false);
+                            if (asReferenceHasValue)
+#endif
+                            {
+                                asReferenceHasValue = GetFieldBoolean(ref asReference, ppma, "AsReference", true);
+                            }
+                            GetFieldBoolean(ref dynamicType, ppma, "DynamicType");
+                            if (done = tagIsPinned = fieldNumber > 0) break; // note minAcceptFieldNumber only applies to non-proto
+                        }
+                    }
+                }
+            }
+
+            if (!ignore && !done && HasFamily(family, AttributeFamily.DataContractSerialier))
+            {
+                attrib = GetAttribute(attribs, "System.Runtime.Serialization.DataMemberAttribute");
+                if (attrib != null)
+                {
+                    GetFieldNumber(ref fieldNumber, attrib, "Order");
+                    GetFieldName(ref name, attrib, "Name");
+                    GetFieldBoolean(ref isRequired, attrib, "IsRequired");
+                    done = fieldNumber >= minAcceptFieldNumber;
+                    if (done) fieldNumber += dataMemberOffset; // dataMemberOffset only applies to DCS flags, to allow us to "bump" WCF by a notch
+                }
+            }
+            if (!ignore && !done && HasFamily(family, AttributeFamily.XmlSerializer))
+            {
+                attrib = GetAttribute(attribs, "System.Xml.Serialization.XmlElementAttribute");
+                if(attrib == null) attrib = GetAttribute(attribs, "System.Xml.Serialization.XmlArrayAttribute");
+                GetIgnore(ref ignore, attrib, attribs, "System.Xml.Serialization.XmlIgnoreAttribute");
+                if (attrib != null && !ignore)
+                {
+                    GetFieldNumber(ref fieldNumber, attrib, "Order");
+                    GetFieldName(ref name, attrib, "ElementName");
+                    done = fieldNumber >= minAcceptFieldNumber;
+                }                
+            }
+            if (!ignore && !done)
+            {
+                if (GetAttribute(attribs, "System.NonSerializedAttribute") != null) ignore = true;
+            }
+            if (ignore || (fieldNumber < minAcceptFieldNumber && !forced)) return null;
+            ProtoMemberAttribute result = new ProtoMemberAttribute(fieldNumber, forced || inferByTagName);
+            result.AsReference = asReference;
+            result.AsReferenceHasValue = asReferenceHasValue;
+            result.DataFormat = dataFormat;
+            result.DynamicType = dynamicType;
+            result.IsPacked = isPacked;
+            result.OverwriteList = overwriteList;
+            result.IsRequired = isRequired;
+            result.Name = Helpers.IsNullOrEmpty(name) ? member.Name : name;
+            result.Member = member;
+            result.TagIsPinned = tagIsPinned;
+            return result;
+        }
+        
+        private ValueMember ApplyDefaultBehaviour(bool isEnum, ProtoMemberAttribute normalizedAttribute)
+        {
+            MemberInfo member;
+            if (normalizedAttribute == null || (member = normalizedAttribute.Member) == null) return null; // nix
+
+            Type effectiveType = Helpers.GetMemberType(member);
+
+            
+            Type itemType = null;
+            Type defaultType = null;
+
+            // check for list types
+            ResolveListTypes(model, effectiveType, ref itemType, ref defaultType);
+            // but take it back if it is explicitly excluded
+            if(itemType != null)
+            { // looks like a list, but double check for IgnoreListHandling
+                int idx = model.FindOrAddAuto(effectiveType, false, true, false);
+                if(idx >= 0 && model[effectiveType].IgnoreListHandling)
+                {
+                    itemType = null;
+                    defaultType = null;
+                }
+            }
+            AttributeMap[] attribs = AttributeMap.Create(model, member, true);
+            AttributeMap attrib;
+
+            object defaultValue = null;
+            // implicit zero default
+            if (model.UseImplicitZeroDefaults)
+            {
+                switch (Helpers.GetTypeCode(effectiveType))
+                {
+                    case ProtoTypeCode.Boolean: defaultValue = false; break;
+                    case ProtoTypeCode.Decimal: defaultValue = (decimal)0; break;
+                    case ProtoTypeCode.Single: defaultValue = (float)0; break;
+                    case ProtoTypeCode.Double: defaultValue = (double)0; break;
+                    case ProtoTypeCode.Byte: defaultValue = (byte)0; break;
+                    case ProtoTypeCode.Char: defaultValue = (char)0; break;
+                    case ProtoTypeCode.Int16: defaultValue = (short)0; break;
+                    case ProtoTypeCode.Int32: defaultValue = (int)0; break;
+                    case ProtoTypeCode.Int64: defaultValue = (long)0; break;
+                    case ProtoTypeCode.SByte: defaultValue = (sbyte)0; break;
+                    case ProtoTypeCode.UInt16: defaultValue = (ushort)0; break;
+                    case ProtoTypeCode.UInt32: defaultValue = (uint)0; break;
+                    case ProtoTypeCode.UInt64: defaultValue = (ulong)0; break;
+                    case ProtoTypeCode.TimeSpan: defaultValue = TimeSpan.Zero; break;
+                    case ProtoTypeCode.Guid: defaultValue = Guid.Empty; break;
+                }
+            }
+            if ((attrib = GetAttribute(attribs, "System.ComponentModel.DefaultValueAttribute")) != null)
+            {
+                object tmp;
+                if(attrib.TryGet("Value", out tmp)) defaultValue = tmp;
+            }
+            ValueMember vm = ((isEnum || normalizedAttribute.Tag > 0))
+                ? new ValueMember(model, type, normalizedAttribute.Tag, member, effectiveType, itemType, defaultType, normalizedAttribute.DataFormat, defaultValue)
+                    : null;
+            if (vm != null)
+            {
+#if WINRT
+                TypeInfo finalType = typeInfo;
+#else
+                Type finalType = type;
+#endif
+                PropertyInfo prop = Helpers.GetProperty(finalType, member.Name + "Specified", true);
+                MethodInfo getMethod = Helpers.GetGetMethod(prop, true, true);
+                if (getMethod == null || getMethod.IsStatic) prop = null;
+                if (prop != null)
+                {
+                    vm.SetSpecified(getMethod, Helpers.GetSetMethod(prop, true, true));
+                }
+                else
+                {
+                    MethodInfo method = Helpers.GetInstanceMethod(finalType, "ShouldSerialize" + member.Name, Helpers.EmptyTypes);
+                    if (method != null && method.ReturnType == model.MapType(typeof(bool)))
+                    {
+                        vm.SetSpecified(method, null);
+                    }
+                }
+                if (!Helpers.IsNullOrEmpty(normalizedAttribute.Name)) vm.SetName(normalizedAttribute.Name);
+                vm.IsPacked = normalizedAttribute.IsPacked;
+                vm.IsRequired = normalizedAttribute.IsRequired;
+                vm.OverwriteList = normalizedAttribute.OverwriteList;
+                if (normalizedAttribute.AsReferenceHasValue)
+                {
+                    vm.AsReference = normalizedAttribute.AsReference;
+                }
+                vm.DynamicType = normalizedAttribute.DynamicType;
+            }
+            return vm;
+        }
+
+        private static void GetDataFormat(ref DataFormat value, AttributeMap attrib, string memberName)
+        {
+            if ((attrib == null) || (value != DataFormat.Default)) return;
+            object obj;
+            if (attrib.TryGet(memberName, out obj) && obj != null) value = (DataFormat)obj;
+        }
+
+        private static void GetIgnore(ref bool ignore, AttributeMap attrib, AttributeMap[] attribs, string fullName)
+        {
+            if (ignore || attrib == null) return;
+            ignore = GetAttribute(attribs, fullName) != null;
+            return;
+        }
+
+        private static void GetFieldBoolean(ref bool value, AttributeMap attrib, string memberName)
+        {
+            GetFieldBoolean(ref value, attrib, memberName, true);
+        }
+        private static bool GetFieldBoolean(ref bool value, AttributeMap attrib, string memberName, bool publicOnly)
+        {
+            if (attrib == null) return false;
+            if (value) return true;
+            object obj;
+            if (attrib.TryGet(memberName, publicOnly, out obj) && obj != null)
+            {
+                value = (bool)obj;
+                return true;
+            }
+            return false;
+        }
+
+        private static void GetFieldNumber(ref int value, AttributeMap attrib, string memberName)
+        {
+            if (attrib == null || value > 0) return;
+            object obj;
+            if (attrib.TryGet(memberName, out obj) && obj != null) value = (int)obj;
+        }
+        private static void GetFieldName(ref string name, AttributeMap attrib, string memberName)
+        {
+            if (attrib == null || !Helpers.IsNullOrEmpty(name)) return;
+            object obj;
+            if (attrib.TryGet(memberName, out obj) && obj != null) name = (string)obj;
+        }
+
+        private static AttributeMap GetAttribute(AttributeMap[] attribs, string fullName)
+        {
+            for (int i = 0; i < attribs.Length; i++)
+            {
+                AttributeMap attrib = attribs[i];
+                if (attrib != null && attrib.AttributeType.FullName == fullName) return attrib;
+            }
+            return null;
+        }
+        /// <summary>
+        /// Adds a member (by name) to the MetaType
+        /// </summary>        
+        public MetaType Add(int fieldNumber, string memberName)
+        {
+            AddField(fieldNumber, memberName, null, null, null);
+            return this;
+        }
+        /// <summary>
+        /// Adds a member (by name) to the MetaType, returning the ValueMember rather than the fluent API.
+        /// This is otherwise identical to Add.
+        /// </summary>
+        public ValueMember AddField(int fieldNumber, string memberName)
+        {
+            return AddField(fieldNumber, memberName, null, null, null);
+        }
+        /// <summary>
+        /// Gets or sets whether the type should use a parameterless constructor (the default),
+        /// or whether the type should skip the constructor completely. This option is not supported
+        /// on compact-framework.
+        /// </summary>
+        public bool UseConstructor
+        { // negated to have defaults as flat zero
+            get { return !HasFlag(OPTIONS_SkipConstructor); }
+            set { SetFlag(OPTIONS_SkipConstructor, !value, true); }
+        }
+        /// <summary>
+        /// The concrete type to create when a new instance of this type is needed; this may be useful when dealing
+        /// with dynamic proxies, or with interface-based APIs
+        /// </summary>
+        public Type ConstructType
+        {
+            get { return constructType; }
+            set
+            {
+                ThrowIfFrozen();
+                constructType = value;
+            }
+        }
+        private Type constructType;
+        /// <summary>
+        /// Adds a member (by name) to the MetaType
+        /// </summary>     
+        public MetaType Add(string memberName)
+        {
+            Add(GetNextFieldNumber(), memberName);
+            return this;
+        }
+        Type surrogate;
+        /// <summary>
+        /// Performs serialization of this type via a surrogate; all
+        /// other serialization options are ignored and handled
+        /// by the surrogate's configuration.
+        /// </summary>
+        public void SetSurrogate(Type surrogateType)
+        {
+            if (surrogateType == type) surrogateType = null;
+            if (surrogateType != null)
+            {
+                // note that BuildSerializer checks the **CURRENT TYPE** is OK to be surrogated
+                if (surrogateType != null && Helpers.IsAssignableFrom(model.MapType(typeof(IEnumerable)), surrogateType))
+                {
+                    throw new ArgumentException("Repeated data (a list, collection, etc) has inbuilt behaviour and cannot be used as a surrogate");
+                }
+            }
+            ThrowIfFrozen();
+            this.surrogate = surrogateType;
+            // no point in offering chaining; no options are respected
+        }
+
+        internal MetaType GetSurrogateOrSelf()
+        {
+            if (surrogate != null) return model[surrogate];
+            return this;
+        }
+        internal MetaType GetSurrogateOrBaseOrSelf(bool deep) {
+            if(surrogate != null) return model[surrogate];
+            MetaType snapshot = this.baseType;
+            if (snapshot != null)
+            {
+                if (deep)
+                {
+                    MetaType tmp;
+                    do
+                    {
+                        tmp = snapshot;
+                        snapshot = snapshot.baseType;
+                    } while(snapshot != null);
+                    return tmp;
+                }
+                return snapshot;
+            }
+            return this;
+        }
+        
+        private int GetNextFieldNumber()
+        {
+            int maxField = 0;
+            foreach (ValueMember member in fields)
+            {
+                if (member.FieldNumber > maxField) maxField = member.FieldNumber;
+            }
+            if (subTypes != null)
+            {
+                foreach (SubType subType in subTypes)
+                {
+                    if (subType.FieldNumber > maxField) maxField = subType.FieldNumber;
+                }
+            }
+            return maxField + 1;
+        }
+        /// <summary>
+        /// Adds a set of members (by name) to the MetaType
+        /// </summary>     
+        public MetaType Add(params string[] memberNames)
+        {
+            if (memberNames == null) throw new ArgumentNullException("memberNames");
+            int next = GetNextFieldNumber();
+            for (int i = 0; i < memberNames.Length; i++)
+            {
+                Add(next++, memberNames[i]);
+            }
+            return this;
+        }
+
+
+        /// <summary>
+        /// Adds a member (by name) to the MetaType
+        /// </summary>        
+        public MetaType Add(int fieldNumber, string memberName, object defaultValue)
+        {
+            AddField(fieldNumber, memberName, null, null, defaultValue);
+            return this;
+        }
+
+        /// <summary>
+        /// Adds a member (by name) to the MetaType, including an itemType and defaultType for representing lists
+        /// </summary>
+        public MetaType Add(int fieldNumber, string memberName, Type itemType, Type defaultType)
+        {
+            AddField(fieldNumber, memberName, itemType, defaultType, null);
+            return this;
+        }
+
+        /// <summary>
+        /// Adds a member (by name) to the MetaType, including an itemType and defaultType for representing lists, returning the ValueMember rather than the fluent API.
+        /// This is otherwise identical to Add.
+        /// </summary>
+        public ValueMember AddField(int fieldNumber, string memberName, Type itemType, Type defaultType)
+        {
+            return AddField(fieldNumber, memberName, itemType, defaultType, null);
+        }
+        
+        private ValueMember AddField(int fieldNumber, string memberName, Type itemType, Type defaultType, object defaultValue)
+        {
+            MemberInfo mi = null;
+#if WINRT
+            mi = Helpers.IsEnum(type) ? type.GetTypeInfo().GetDeclaredField(memberName) : Helpers.GetInstanceMember(type.GetTypeInfo(), memberName);
+
+#else
+            MemberInfo[] members = type.GetMember(memberName, Helpers.IsEnum(type) ? BindingFlags.Static | BindingFlags.Public : BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
+            if(members != null && members.Length == 1) mi = members[0];
+#endif
+            if (mi == null) throw new ArgumentException("Unable to determine member: " + memberName, "memberName");
+
+            Type miType;
+#if WINRT || PORTABLE
+            PropertyInfo pi = mi as PropertyInfo;
+            if (pi == null)
+            {
+                FieldInfo fi = mi as FieldInfo;
+                if (fi == null)
+                {
+                    throw new NotSupportedException(mi.GetType().Name);
+                }
+                else
+                {
+                    miType = fi.FieldType;
+                }
+            }
+            else
+            {
+                miType = pi.PropertyType;
+            }
+#else   
+            switch (mi.MemberType)
+            {
+                case MemberTypes.Field:
+                    miType = ((FieldInfo)mi).FieldType; break;
+                case MemberTypes.Property:
+                    miType = ((PropertyInfo)mi).PropertyType; break;
+                default:
+                    throw new NotSupportedException(mi.MemberType.ToString());
+            }
+#endif
+            ResolveListTypes(model, miType, ref itemType, ref defaultType);
+            ValueMember newField = new ValueMember(model, type, fieldNumber, mi, miType, itemType, defaultType, DataFormat.Default, defaultValue);
+            Add(newField);
+            return newField;
+        }
+
+        internal static void ResolveListTypes(TypeModel model, Type type, ref Type itemType, ref Type defaultType)
+        {
+            if (type == null) return;
+            // handle arrays
+            if (type.IsArray)
+            {
+                if (type.GetArrayRank() != 1)
+                {
+                    throw new NotSupportedException("Multi-dimension arrays are supported");
+                }
+                itemType = type.GetElementType();
+                if (itemType == model.MapType(typeof(byte)))
+                {
+                    defaultType = itemType = null;
+                }
+                else
+                {
+                    defaultType = type;
+                }
+            }
+            // handle lists
+            if (itemType == null) { itemType = TypeModel.GetListItemType(model, type); }
+
+            // check for nested data (not allowed)
+            if (itemType != null)
+            {
+                Type nestedItemType = null, nestedDefaultType = null;
+                ResolveListTypes(model, itemType, ref nestedItemType, ref nestedDefaultType);
+                if (nestedItemType != null)
+                {
+                    throw TypeModel.CreateNestedListsNotSupported();
+                }
+            }
+
+            if (itemType != null && defaultType == null)
+            {
+#if WINRT
+                TypeInfo typeInfo = type.GetTypeInfo();
+                if (typeInfo.IsClass && !typeInfo.IsAbstract && Helpers.GetConstructor(typeInfo, Helpers.EmptyTypes, true) != null)
+#else
+                if (type.IsClass && !type.IsAbstract && Helpers.GetConstructor(type, Helpers.EmptyTypes, true) != null)
+#endif
+                {
+                    defaultType = type;
+                }
+                if (defaultType == null)
+                {
+#if WINRT
+                    if (typeInfo.IsInterface)
+#else
+                    if (type.IsInterface)
+#endif
+                    {
+#if NO_GENERICS
+                        defaultType = typeof(ArrayList);
+#else
+                        Type[] genArgs;
+#if WINRT
+                        if (typeInfo.IsGenericType && type.GetGenericTypeDefinition() == typeof(System.Collections.Generic.IDictionary<,>)
+                            && itemType == typeof(System.Collections.Generic.KeyValuePair<,>).MakeGenericType(genArgs = typeInfo.GenericTypeArguments))
+#else
+                        if (type.IsGenericType && type.GetGenericTypeDefinition() == model.MapType(typeof(System.Collections.Generic.IDictionary<,>))
+                            && itemType == model.MapType(typeof(System.Collections.Generic.KeyValuePair<,>)).MakeGenericType(genArgs = type.GetGenericArguments()))
+#endif
+                        {
+                            defaultType = model.MapType(typeof(System.Collections.Generic.Dictionary<,>)).MakeGenericType(genArgs);
+                        }
+                        else
+                        {
+                            defaultType = model.MapType(typeof(System.Collections.Generic.List<>)).MakeGenericType(itemType);
+                        }
+#endif
+                    }
+                }
+                // verify that the default type is appropriate
+                if (defaultType != null && !Helpers.IsAssignableFrom(type, defaultType)) { defaultType = null; }
+            }
+        }
+
+        private void Add(ValueMember member) {
+            int opaqueToken = 0;
+            try {
+                model.TakeLock(ref opaqueToken);
+                ThrowIfFrozen();
+                fields.Add(member);
+            } finally
+            {
+                model.ReleaseLock(opaqueToken);
+            }
+        }
+        /// <summary>
+        /// Returns the ValueMember that matchs a given field number, or null if not found
+        /// </summary>
+        public ValueMember this[int fieldNumber]
+        {
+            get
+            {
+                foreach (ValueMember member in fields)
+                {
+                    if (member.FieldNumber == fieldNumber) return member;
+                }
+                return null;
+            }
+        }
+        /// <summary>
+        /// Returns the ValueMember that matchs a given member (property/field), or null if not found
+        /// </summary>
+        public ValueMember this[MemberInfo member]
+        {
+            get
+            {
+                if (member == null) return null;
+                foreach (ValueMember x in fields)
+                {
+                    if (x.Member == member) return x;
+                }
+                return null;
+            }
+        }
+        private readonly BasicList fields = new BasicList();
+
+        /// <summary>
+        /// Returns the ValueMember instances associated with this type
+        /// </summary>
+        public ValueMember[] GetFields() {
+            ValueMember[] arr = new ValueMember[fields.Count];
+            fields.CopyTo(arr, 0);
+            Array.Sort(arr, ValueMember.Comparer.Default);
+            return arr;
+        }
+
+        /// <summary>
+        /// Returns the SubType instances associated with this type
+        /// </summary>
+        public SubType[] GetSubtypes()
+        {
+            if (subTypes == null || subTypes.Count == 0) return new SubType[0];
+            SubType[] arr = new SubType[subTypes.Count];
+            subTypes.CopyTo(arr, 0);
+            Array.Sort(arr, SubType.Comparer.Default);
+            return arr;
+        }
+
+#if FEAT_COMPILER && !FX11
+
+        /// <summary>
+        /// Compiles the serializer for this type; this is *not* a full
+        /// standalone compile, but can significantly boost performance
+        /// while allowing additional types to be added.
+        /// </summary>
+        /// <remarks>An in-place compile can access non-public types / members</remarks>
+        public void CompileInPlace()
+        {
+#if FEAT_IKVM
+            // just no nothing, quietely; don't want to break the API
+#else
+            serializer = CompiledSerializer.Wrap(Serializer, model);
+#endif
+        }
+#endif
+
+        internal bool IsDefined(int fieldNumber)
+        {
+            foreach (ValueMember field in fields)
+            {
+                if (field.FieldNumber == fieldNumber) return true;
+            }
+            return false;
+        }
+
+        internal int GetKey(bool demand, bool getBaseKey)
+        {
+            return model.GetKey(type, demand, getBaseKey);
+        }
+
+
+
+        internal EnumSerializer.EnumPair[] GetEnumMap()
+        {
+            if (HasFlag(OPTIONS_EnumPassThru)) return null;
+            EnumSerializer.EnumPair[] result = new EnumSerializer.EnumPair[fields.Count];
+            for (int i = 0; i < result.Length; i++)
+            {
+                ValueMember member = (ValueMember) fields[i];
+                int wireValue = member.FieldNumber;
+                object value = member.GetRawEnumValue();
+                result[i] = new EnumSerializer.EnumPair(wireValue, value, member.MemberType);
+            }
+            return result;
+        }
+
+
+        /// <summary>
+        /// Gets or sets a value indicating that an enum should be treated directly as an int/short/etc, rather
+        /// than enforcing .proto enum rules. This is useful *in particul* for [Flags] enums.
+        /// </summary>
+        public bool EnumPassthru
+        {
+            get { return HasFlag(OPTIONS_EnumPassThru); }
+            set { SetFlag(OPTIONS_EnumPassThru, value, true); }
+        }
+
+        /// <summary>
+        /// Gets or sets a value indicating that this type should NOT be treated as a list, even if it has
+        /// familiar list-like characteristics (enumerable, add, etc)
+        /// </summary>
+        public bool IgnoreListHandling
+        {
+            get { return HasFlag(OPTIONS_IgnoreListHandling); }
+            set { SetFlag(OPTIONS_IgnoreListHandling, value, true); }
+        }
+
+        internal bool Pending
+        {
+            get { return HasFlag(OPTIONS_Pending); }
+            set { SetFlag(OPTIONS_Pending, value, false); }
+        }
+
+        private const byte
+            OPTIONS_Pending = 1,
+            OPTIONS_EnumPassThru = 2,
+            OPTIONS_Frozen = 4,
+            OPTIONS_PrivateOnApi = 8,
+            OPTIONS_SkipConstructor = 16,
+            OPTIONS_AsReferenceDefault = 32,
+            OPTIONS_AutoTuple = 64,
+            OPTIONS_IgnoreListHandling = 128;
+
+        private volatile byte flags;
+        private bool HasFlag(byte flag) { return (flags & flag) == flag; }
+        private void SetFlag(byte flag, bool value, bool throwIfFrozen)
+        {
+            if (throwIfFrozen && HasFlag(flag) != value)
+            {
+                ThrowIfFrozen();
+            }
+            if (value)
+                flags |= flag;
+            else
+                flags = (byte)(flags & ~flag);
+        }
+
+        internal static MetaType GetRootType(MetaType source)
+        {
+           
+            while (source.serializer != null)
+            {
+                MetaType tmp = source.baseType;
+                if (tmp == null) return source;
+                source = tmp; // else loop until we reach something that isn't generated, or is the root
+            }
+
+            // now we get into uncertain territory
+            RuntimeTypeModel model = source.model;
+            int opaqueToken = 0;
+            try {
+                model.TakeLock(ref opaqueToken);
+
+                MetaType tmp;
+                while ((tmp = source.baseType) != null) source = tmp;
+                return source;
+
+            } finally {
+                model.ReleaseLock(opaqueToken);
+            }
+        }
+
+        internal bool IsPrepared()
+        {
+            #if FEAT_COMPILER && !FEAT_IKVM && !FX11
+            return serializer is CompiledSerializer;
+            #else
+            return false;
+            #endif
+        }
+
+        internal System.Collections.IEnumerable Fields { get { return this.fields; } }
+
+        internal static System.Text.StringBuilder NewLine(System.Text.StringBuilder builder, int indent)
+        {
+            return Helpers.AppendLine(builder).Append(' ', indent*3);
+        }
+        internal bool IsAutoTuple
+        {
+            get { return HasFlag(OPTIONS_AutoTuple); }
+        }
+        internal void WriteSchema(System.Text.StringBuilder builder, int indent, ref bool requiresBclImport)
+        {
+            if (surrogate != null) return; // nothing to write
+
+
+            ValueMember[] fieldsArr = new ValueMember[fields.Count];
+            fields.CopyTo(fieldsArr, 0);
+            Array.Sort(fieldsArr, ValueMember.Comparer.Default);
+
+            if (IsList)
+            {
+                string itemTypeName = model.GetSchemaTypeName(TypeModel.GetListItemType(model, type), DataFormat.Default, false, false, ref requiresBclImport);
+                NewLine(builder, indent).Append("message ").Append(GetSchemaTypeName()).Append(" {");
+                NewLine(builder, indent + 1).Append("repeated ").Append(itemTypeName).Append(" items = 1;");
+                NewLine(builder, indent).Append('}');
+            }
+            else if (IsAutoTuple)
+            { // key-value-pair etc
+                MemberInfo[] mapping;
+                if(ResolveTupleConstructor(type, out mapping) != null)
+                {
+                    NewLine(builder, indent).Append("message ").Append(GetSchemaTypeName()).Append(" {");
+                    for(int i = 0 ; i < mapping.Length ; i++)
+                    {
+                        Type effectiveType;
+                        if(mapping[i] is PropertyInfo)
+                        {
+                            effectiveType = ((PropertyInfo) mapping[i]).PropertyType;
+                        } else if (mapping[i] is FieldInfo)
+                        {
+                            effectiveType = ((FieldInfo) mapping[i]).FieldType;
+                        } else
+                        {
+                            throw new NotSupportedException("Unknown member type: " + mapping[i].GetType().Name);
+                        }
+                        NewLine(builder, indent + 1).Append("optional ").Append(model.GetSchemaTypeName(effectiveType, DataFormat.Default, false, false, ref requiresBclImport).Replace('.','_'))
+                            .Append(' ').Append(mapping[i].Name).Append(" = ").Append(i + 1).Append(';');
+                    }
+                    NewLine(builder, indent).Append('}');
+                }
+            }
+            else if(Helpers.IsEnum(type))
+            {
+                NewLine(builder, indent).Append("enum ").Append(GetSchemaTypeName()).Append(" {");
+                if (fieldsArr.Length == 0 && EnumPassthru) {
+                    if (type
+#if WINRT
+                    .GetTypeInfo()
+#endif
+.IsDefined(model.MapType(typeof(FlagsAttribute)), false))
+                    {
+                        NewLine(builder, indent + 1).Append("// this is a composite/flags enumeration");
+                    }
+                    else
+                    {
+                        NewLine(builder, indent + 1).Append("// this enumeration will be passed as a raw value");
+                    }
+                    foreach(FieldInfo field in
+#if WINRT
+                        type.GetRuntimeFields()
+#else
+                        type.GetFields()
+#endif
+                        
+                        )
+                    {
+                        if(field.IsStatic && field.IsLiteral)
+                        {
+                            object enumVal;
+#if WINRT || PORTABLE || CF || FX11
+                            enumVal = field.GetValue(null);
+#else
+                            enumVal = field.GetRawConstantValue();
+#endif
+                            NewLine(builder, indent + 1).Append(field.Name).Append(" = ").Append(enumVal).Append(";");
+                        }
+                    }
+                    
+                }
+                else
+                {
+                    foreach (ValueMember member in fieldsArr)
+                    {
+                        NewLine(builder, indent + 1).Append(member.Name).Append(" = ").Append(member.FieldNumber).Append(';');
+                    }
+                }
+                NewLine(builder, indent).Append('}');
+            } else
+            {
+                NewLine(builder, indent).Append("message ").Append(GetSchemaTypeName()).Append(" {");
+                foreach (ValueMember member in fieldsArr)
+                {
+                    string ordinality = member.ItemType != null ? "repeated" : member.IsRequired ? "required" : "optional";
+                    NewLine(builder, indent + 1).Append(ordinality).Append(' ');
+                    if (member.DataFormat == DataFormat.Group) builder.Append("group ");
+                    string schemaTypeName = member.GetSchemaTypeName(true, ref requiresBclImport);
+                    builder.Append(schemaTypeName).Append(" ")
+                         .Append(member.Name).Append(" = ").Append(member.FieldNumber);
+                    if(member.DefaultValue != null)
+                    {
+                        if (member.DefaultValue is string)
+                        {
+                            builder.Append(" [default = \"").Append(member.DefaultValue).Append("\"]");
+                        }
+                        else if(member.DefaultValue is bool)
+                        {   // need to be lower case (issue 304)
+                            builder.Append((bool)member.DefaultValue ? " [default = true]" : " [default = false]");
+                        }
+                        else
+                        {
+                            builder.Append(" [default = ").Append(member.DefaultValue).Append(']');
+                        }
+                    }
+                    if(member.ItemType != null && member.IsPacked)
+                    {
+                        builder.Append(" [packed=true]");
+                    }
+                    builder.Append(';');
+                    if (schemaTypeName == "bcl.NetObjectProxy" && member.AsReference && !member.DynamicType) // we know what it is; tell the user
+                    {
+                        builder.Append(" // reference-tracked ").Append(member.GetSchemaTypeName(false, ref requiresBclImport));
+                    }
+                }
+                if (subTypes != null && subTypes.Count != 0)
+                {
+                    NewLine(builder, indent + 1).Append("// the following represent sub-types; at most 1 should have a value");
+                    SubType[] subTypeArr = new SubType[subTypes.Count];
+                    subTypes.CopyTo(subTypeArr, 0);
+                    Array.Sort(subTypeArr, SubType.Comparer.Default);
+                    foreach (SubType subType in subTypeArr)
+                    {
+                        string subTypeName = subType.DerivedType.GetSchemaTypeName();
+                        NewLine(builder, indent + 1).Append("optional ").Append(subTypeName)
+                            .Append(" ").Append(subTypeName).Append(" = ").Append(subType.FieldNumber).Append(';');
+                    }
+                }
+                NewLine(builder, indent).Append('}');
+            }
+        }
+    }
+}
+#endif

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/Meta/MetaType.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 853a227c3b0c9514aad6a5386f422cc2
+timeCreated: 1515899113
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 2005 - 0
Unity/Assets/Plugins/protobuf-net/Meta/RuntimeTypeModel.cs

@@ -0,0 +1,2005 @@
+#if !NO_RUNTIME
+using System;
+using System.Collections;
+using System.Text;
+
+#if FEAT_IKVM
+using Type = IKVM.Reflection.Type;
+using IKVM.Reflection;
+using IKVM.Reflection.Emit;
+#else
+using System.Reflection;
+#if FEAT_COMPILER
+using System.Reflection.Emit;
+#endif
+#endif
+
+using ProtoBuf.Serializers;
+using System.Threading;
+using System.IO;
+
+
+namespace ProtoBuf.Meta
+{
+    /// <summary>
+    /// Provides protobuf serialization support for a number of types that can be defined at runtime
+    /// </summary>
+    public sealed class RuntimeTypeModel : TypeModel
+    {
+        private byte options;
+        private const byte
+           OPTIONS_InferTagFromNameDefault = 1,
+           OPTIONS_IsDefaultModel = 2,
+           OPTIONS_Frozen = 4,
+           OPTIONS_AutoAddMissingTypes = 8,
+#if FEAT_COMPILER && !FX11
+           OPTIONS_AutoCompile = 16,
+#endif
+           OPTIONS_UseImplicitZeroDefaults = 32,
+           OPTIONS_AllowParseableTypes = 64,
+           OPTIONS_AutoAddProtoContractTypesOnly = 128;
+        private bool GetOption(byte option)
+        {
+            return (options & option) == option;
+        }
+        private void SetOption(byte option, bool value)
+        {
+            if (value) options |= option;
+            else options &= (byte)~option;
+        }
+        /// <summary>
+        /// Global default that
+        /// enables/disables automatic tag generation based on the existing name / order
+        /// of the defined members. See <seealso cref="ProtoContractAttribute.InferTagFromName"/>
+        /// for usage and <b>important warning</b> / explanation.
+        /// You must set the global default before attempting to serialize/deserialize any
+        /// impacted type.
+        /// </summary>
+        public bool InferTagFromNameDefault
+        {
+            get { return GetOption(OPTIONS_InferTagFromNameDefault); }
+            set { SetOption(OPTIONS_InferTagFromNameDefault, value); }
+        }
+
+        /// <summary>
+        /// Global default that determines whether types are considered serializable
+        /// if they have [DataContract] / [XmlType]. With this enabled, <b>ONLY</b>
+        /// types marked as [ProtoContract] are added automatically.
+        /// </summary>
+        public bool AutoAddProtoContractTypesOnly
+        {
+            get { return GetOption(OPTIONS_AutoAddProtoContractTypesOnly); }
+            set { SetOption(OPTIONS_AutoAddProtoContractTypesOnly, value); }
+        }
+
+        /// <summary>
+        /// Global switch that enables or disables the implicit
+        /// handling of "zero defaults"; meanning: if no other default is specified,
+        /// it assumes bools always default to false, integers to zero, etc.
+        /// 
+        /// If this is disabled, no such assumptions are made and only *explicit*
+        /// default values are processed. This is enabled by default to 
+        /// preserve similar logic to v1.
+        /// </summary>
+        public bool UseImplicitZeroDefaults
+        {
+            get {return GetOption(OPTIONS_UseImplicitZeroDefaults);}
+            set {
+                if (!value && GetOption(OPTIONS_IsDefaultModel))
+                {
+                    throw new InvalidOperationException("UseImplicitZeroDefaults cannot be disabled on the default model");
+                }
+                SetOption(OPTIONS_UseImplicitZeroDefaults, value);
+            }
+        }
+
+        /// <summary>
+        /// Global switch that determines whether types with a <c>.ToString()</c> and a <c>Parse(string)</c>
+        /// should be serialized as strings.
+        /// </summary>
+        public bool AllowParseableTypes
+        {
+            get { return GetOption(OPTIONS_AllowParseableTypes); }
+            set { SetOption(OPTIONS_AllowParseableTypes, value); }
+        }
+        
+
+        private sealed class Singleton
+        {
+            private Singleton() { }
+            internal static readonly RuntimeTypeModel Value = new RuntimeTypeModel(true);
+        }
+        /// <summary>
+        /// The default model, used to support ProtoBuf.Serializer
+        /// </summary>
+        public static RuntimeTypeModel Default
+        {
+            get { return Singleton.Value; }
+        }
+        /// <summary>
+        /// Returns a sequence of the Type instances that can be
+        /// processed by this model.
+        /// </summary>
+        public IEnumerable GetTypes() { return types; }
+
+        /// <summary>
+        /// Suggest a .proto definition for the given type
+        /// </summary>
+        /// <param name="type">The type to generate a .proto definition for, or <c>null</c> to generate a .proto that represents the entire model</param>
+        /// <returns>The .proto definition as a string</returns>
+        public override string GetSchema(Type type)
+        {
+            BasicList requiredTypes = new BasicList();
+            MetaType primaryType = null;
+            bool isInbuiltType = false;
+            if (type == null)
+            { // generate for the entire model
+                foreach(MetaType meta in types)
+                {
+                    MetaType tmp = meta.GetSurrogateOrBaseOrSelf(false);
+                    if (!requiredTypes.Contains(tmp))
+                    { // ^^^ note that the type might have been added as a descendent
+                        requiredTypes.Add(tmp);
+                        CascadeDependents(requiredTypes, tmp);
+                    }
+                }
+            }
+            else
+            {
+                Type tmp = Helpers.GetUnderlyingType(type);
+                if (tmp != null) type = tmp;
+
+                WireType defaultWireType;
+                isInbuiltType = (ValueMember.TryGetCoreSerializer(this, DataFormat.Default, type, out defaultWireType, false, false, false, false) != null);
+                if (!isInbuiltType)
+                {
+                    //Agenerate just relative to the supplied type
+                    int index = FindOrAddAuto(type, false, false, false);
+                    if (index < 0) throw new ArgumentException("The type specified is not a contract-type", "type");
+
+                    // get the required types
+                    primaryType = ((MetaType)types[index]).GetSurrogateOrBaseOrSelf(false);
+                    requiredTypes.Add(primaryType);
+                    CascadeDependents(requiredTypes, primaryType);
+                }
+            }
+
+            // use the provided type's namespace for the "package"
+            StringBuilder headerBuilder = new StringBuilder();
+            string package = null;
+
+            if (!isInbuiltType)
+            {
+                IEnumerable typesForNamespace = primaryType == null ? types : requiredTypes;
+                foreach (MetaType meta in typesForNamespace)
+                {
+                    if (meta.IsList) continue;
+                    string tmp = meta.Type.Namespace;
+                    if (!Helpers.IsNullOrEmpty(tmp))
+                    {
+                        if (tmp.StartsWith("System.")) continue;
+                        if (package == null)
+                        { // haven't seen any suggestions yet
+                            package = tmp;
+                        }
+                        else if (package == tmp)
+                        { // that's fine; a repeat of the one we already saw
+                        }
+                        else
+                        { // something else; have confliucting suggestions; abort
+                            package = null;
+                            break;
+                        }
+                    }
+                }
+            }
+
+            if (!Helpers.IsNullOrEmpty(package))
+            {
+                headerBuilder.Append("package ").Append(package).Append(';');
+                Helpers.AppendLine(headerBuilder);
+            }
+
+            bool requiresBclImport = false;
+            StringBuilder bodyBuilder = new StringBuilder();
+            // sort them by schema-name
+            MetaType[] metaTypesArr = new MetaType[requiredTypes.Count];
+            requiredTypes.CopyTo(metaTypesArr, 0);
+            Array.Sort(metaTypesArr, MetaType.Comparer.Default);
+
+            // write the messages
+            if (isInbuiltType)
+            {
+                Helpers.AppendLine(bodyBuilder).Append("message ").Append(type.Name).Append(" {");
+                MetaType.NewLine(bodyBuilder, 1).Append("optional ").Append(GetSchemaTypeName(type, DataFormat.Default, false, false, ref requiresBclImport))
+                    .Append(" value = 1;");
+                Helpers.AppendLine(bodyBuilder).Append('}');
+            }
+            else
+            {
+                for (int i = 0; i < metaTypesArr.Length; i++)
+                {
+                    MetaType tmp = metaTypesArr[i];
+                    if (tmp.IsList && tmp != primaryType) continue;
+                    tmp.WriteSchema(bodyBuilder, 0, ref requiresBclImport);
+                }
+            }
+            if (requiresBclImport)
+            {
+                headerBuilder.Append("import \"bcl.proto\"; // schema for protobuf-net's handling of core .NET types");
+                Helpers.AppendLine(headerBuilder);
+            }
+            return Helpers.AppendLine(headerBuilder.Append(bodyBuilder)).ToString();
+        }
+        private void CascadeDependents(BasicList list, MetaType metaType)
+        {
+            MetaType tmp;
+            if (metaType.IsList)
+            {
+                Type itemType = TypeModel.GetListItemType(this, metaType.Type);
+                WireType defaultWireType;
+                IProtoSerializer coreSerializer = ValueMember.TryGetCoreSerializer(this, DataFormat.Default, itemType, out defaultWireType, false, false, false, false);
+                if (coreSerializer == null)
+                {
+                    int index = FindOrAddAuto(itemType, false, false, false);
+                    if (index >= 0)
+                    {
+                        tmp = ((MetaType)types[index]).GetSurrogateOrBaseOrSelf(false);
+                        if (!list.Contains(tmp))
+                        { // could perhaps also implement as a queue, but this should work OK for sane models
+                            list.Add(tmp);
+                            CascadeDependents(list, tmp);
+                        }
+                    }
+                }
+            }
+            else
+            {
+                if (metaType.IsAutoTuple)
+                {
+                    MemberInfo[] mapping;
+                    if(MetaType.ResolveTupleConstructor(metaType.Type, out mapping) != null)
+                    {
+                        for (int i = 0; i < mapping.Length; i++)
+                        {
+                            Type type = null;
+                            if (mapping[i] is PropertyInfo) type = ((PropertyInfo)mapping[i]).PropertyType;
+                            else if (mapping[i] is FieldInfo) type = ((FieldInfo)mapping[i]).FieldType;
+
+                            WireType defaultWireType;
+                            IProtoSerializer coreSerializer = ValueMember.TryGetCoreSerializer(this, DataFormat.Default, type, out defaultWireType, false, false, false, false);
+                            if (coreSerializer == null)
+                            {
+                                int index = FindOrAddAuto(type, false, false, false);
+                                if (index >= 0)
+                                {
+                                    tmp = ((MetaType)types[index]).GetSurrogateOrBaseOrSelf(false);
+                                    if (!list.Contains(tmp))
+                                    { // could perhaps also implement as a queue, but this should work OK for sane models
+                                        list.Add(tmp);
+                                        CascadeDependents(list, tmp);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+                else
+                {
+                    foreach (ValueMember member in metaType.Fields)
+                    {
+                        Type type = member.ItemType;
+                        if (type == null) type = member.MemberType;
+                        WireType defaultWireType;
+                        IProtoSerializer coreSerializer = ValueMember.TryGetCoreSerializer(this, DataFormat.Default, type, out defaultWireType, false, false, false, false);
+                        if (coreSerializer == null)
+                        {
+                            // is an interesting type
+                            int index = FindOrAddAuto(type, false, false, false);
+                            if (index >= 0)
+                            {
+                                tmp = ((MetaType)types[index]).GetSurrogateOrBaseOrSelf(false);
+                                if (!list.Contains(tmp))
+                                { // could perhaps also implement as a queue, but this should work OK for sane models
+                                    list.Add(tmp);
+                                    CascadeDependents(list, tmp);
+                                }
+                            }
+                        }
+                    }
+                }
+                if (metaType.HasSubtypes)
+                {
+                    foreach (SubType subType in metaType.GetSubtypes())
+                    {
+                        tmp = subType.DerivedType.GetSurrogateOrSelf(); // note: exclude base-types!
+                        if (!list.Contains(tmp))
+                        {
+                            list.Add(tmp);
+                            CascadeDependents(list, tmp);
+                        }
+                    }
+                }
+                tmp = metaType.BaseType;
+                if (tmp != null) tmp = tmp.GetSurrogateOrSelf(); // note: already walking base-types; exclude base
+                if (tmp != null && !list.Contains(tmp))
+                {
+                    list.Add(tmp);
+                    CascadeDependents(list, tmp);
+                }
+            }
+        }
+
+
+        internal RuntimeTypeModel(bool isDefault)
+        {
+#if FEAT_IKVM
+            universe = new IKVM.Reflection.Universe();
+            universe.EnableMissingMemberResolution(); // needed to avoid TypedReference issue on WinRT
+#endif
+            AutoAddMissingTypes = true;
+            UseImplicitZeroDefaults = true;
+            SetOption(OPTIONS_IsDefaultModel, isDefault);
+#if FEAT_COMPILER && !FX11 && !DEBUG
+            AutoCompile = true;
+#endif
+        }
+
+#if FEAT_IKVM
+        readonly IKVM.Reflection.Universe universe;
+        /// <summary>
+        /// Load an assembly into the model's universe
+        /// </summary>
+        public Assembly Load(string path)
+        {
+            return universe.LoadFile(path);
+        }
+        /// <summary>
+        /// Gets the IKVM Universe that relates to this model
+        /// </summary>
+        public Universe Universe { get { return universe; } }
+
+        /// <summary>
+        /// Adds support for an additional type in this model, optionally
+        /// appplying inbuilt patterns. If the type is already known to the
+        /// model, the existing type is returned **without** applying
+        /// any additional behaviour.
+        /// </summary>
+        public MetaType Add(string assemblyQualifiedTypeName, bool applyDefaults)
+        {
+            Type type = universe.GetType(assemblyQualifiedTypeName, true);
+            return Add(type, applyDefaults);
+        }
+        /// <summary>
+        /// Adds support for an additional type in this model, optionally
+        /// appplying inbuilt patterns. If the type is already known to the
+        /// model, the existing type is returned **without** applying
+        /// any additional behaviour.
+        /// </summary>
+        public MetaType Add(System.Type type, bool applyDefaultBehaviour)
+        {
+            return Add(MapType(type), applyDefaultBehaviour);
+        }
+        /// <summary>
+        /// Obtains the MetaType associated with a given Type for the current model,
+        /// allowing additional configuration.
+        /// </summary>
+        public MetaType this[System.Type type] { get { return this[MapType(type)]; } }
+        
+#endif
+
+        /// <summary>
+        /// Obtains the MetaType associated with a given Type for the current model,
+        /// allowing additional configuration.
+        /// </summary>
+        public MetaType this[Type type] { get { return (MetaType)types[FindOrAddAuto(type, true, false, false)]; } }
+        
+        internal MetaType FindWithoutAdd(Type type)
+        {
+            // this list is thread-safe for reading
+            foreach (MetaType metaType in types)
+            {
+                if (metaType.Type == type)
+                {
+                    if (metaType.Pending) WaitOnLock(metaType);
+                    return metaType;
+                }
+            }
+            // if that failed, check for a proxy
+            Type underlyingType = ResolveProxies(type);
+            return underlyingType == null ? null : FindWithoutAdd(underlyingType);
+        }
+
+        static readonly BasicList.MatchPredicate
+            MetaTypeFinder = new BasicList.MatchPredicate(MetaTypeFinderImpl),
+            BasicTypeFinder = new BasicList.MatchPredicate(BasicTypeFinderImpl);
+        static bool MetaTypeFinderImpl(object value, object ctx)
+        {
+            return ((MetaType)value).Type == (Type)ctx;
+        }
+        static bool BasicTypeFinderImpl(object value, object ctx)
+        {
+            return ((BasicType)value).Type == (Type)ctx;
+        }
+
+        private void WaitOnLock(MetaType type)
+        {
+            int opaqueToken = 0;
+            try
+            {
+                TakeLock(ref opaqueToken);
+            }
+            finally
+            {
+                ReleaseLock(opaqueToken);
+            }
+        }
+        BasicList basicTypes = new BasicList();
+
+        sealed class BasicType
+        {
+            private readonly Type type;
+            public Type Type { get { return type; } }
+            private readonly IProtoSerializer serializer;
+            public IProtoSerializer Serializer { get { return serializer; } }
+            public BasicType(Type type, IProtoSerializer serializer)
+            {
+                this.type = type;
+                this.serializer = serializer;
+            }
+        }
+        internal IProtoSerializer TryGetBasicTypeSerializer(Type type)
+        {
+            int idx = basicTypes.IndexOf(BasicTypeFinder, type);
+
+            if (idx >= 0) return ((BasicType)basicTypes[idx]).Serializer;
+
+            lock(basicTypes)
+            { // don't need a full model lock for this
+
+                // double-checked
+                idx = basicTypes.IndexOf(BasicTypeFinder, type);
+                if (idx >= 0) return ((BasicType)basicTypes[idx]).Serializer;
+
+                WireType defaultWireType;
+                MetaType.AttributeFamily family = MetaType.GetContractFamily(this, type, null);
+                IProtoSerializer ser = family == MetaType.AttributeFamily.None
+                    ? ValueMember.TryGetCoreSerializer(this, DataFormat.Default, type, out defaultWireType, false, false, false, false)
+                    : null;
+
+                if(ser != null) basicTypes.Add(new BasicType(type, ser));
+                return ser;
+            }
+
+        }
+
+        internal int FindOrAddAuto(Type type, bool demand, bool addWithContractOnly, bool addEvenIfAutoDisabled)
+        {
+            int key = types.IndexOf(MetaTypeFinder, type);
+            MetaType metaType;
+
+            // the fast happy path: meta-types we've already seen
+            if (key >= 0)
+            {
+                metaType = (MetaType)types[key];
+                if (metaType.Pending)
+                {
+                    WaitOnLock(metaType);
+                }
+                return key;
+            }
+
+            // the fast fail path: types that will never have a meta-type
+            bool shouldAdd = AutoAddMissingTypes || addEvenIfAutoDisabled;
+
+            if (!Helpers.IsEnum(type) && TryGetBasicTypeSerializer(type) != null)
+            {
+                if (shouldAdd && !addWithContractOnly) throw MetaType.InbuiltType(type);
+                return -1; // this will never be a meta-type
+            }
+
+            // otherwise: we don't yet know
+
+            // check for proxy types
+            Type underlyingType = ResolveProxies(type);
+            if (underlyingType != null)
+            {
+                key = types.IndexOf(MetaTypeFinder, underlyingType);
+                type = underlyingType; // if new added, make it reflect the underlying type
+            }
+
+            if (key < 0)
+            {
+                int opaqueToken = 0;
+                try
+                {
+                    TakeLock(ref opaqueToken);
+                    // try to recognise a few familiar patterns...
+                    if ((metaType = RecogniseCommonTypes(type)) == null)
+                    { // otherwise, check if it is a contract
+                        MetaType.AttributeFamily family = MetaType.GetContractFamily(this, type, null);
+                        if (family == MetaType.AttributeFamily.AutoTuple)
+                        {
+                            shouldAdd = addEvenIfAutoDisabled = true; // always add basic tuples, such as KeyValuePair
+                        }
+
+                        if (!shouldAdd || (
+                            !Helpers.IsEnum(type) && addWithContractOnly && family == MetaType.AttributeFamily.None)
+                            )
+                        {
+                            if (demand) ThrowUnexpectedType(type);
+                            return key;
+                        }
+                        metaType = Create(type);
+                    }
+                    metaType.Pending = true;                    
+                    bool weAdded = false;
+
+                    // double-checked
+                    int winner = types.IndexOf(MetaTypeFinder, type);
+                    if (winner < 0)
+                    {
+                        ThrowIfFrozen();
+                        key = types.Add(metaType);
+                        weAdded = true;
+                    }
+                    else
+                    {
+                        key = winner;
+                    }
+                    if (weAdded)
+                    {
+                        metaType.ApplyDefaultBehaviour();
+                        metaType.Pending = false;
+                    }
+                }
+                finally
+                {
+                    ReleaseLock(opaqueToken);
+                }
+            }
+            return key;
+        }
+
+        private MetaType RecogniseCommonTypes(Type type)
+        {
+//#if !NO_GENERICS
+//            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(System.Collections.Generic.KeyValuePair<,>))
+//            {
+//                MetaType mt = new MetaType(this, type);
+
+//                Type surrogate = typeof (KeyValuePairSurrogate<,>).MakeGenericType(type.GetGenericArguments());
+
+//                mt.SetSurrogate(surrogate);
+//                mt.IncludeSerializerMethod = false;
+//                mt.Freeze();
+
+//                MetaType surrogateMeta = (MetaType)types[FindOrAddAuto(surrogate, true, true, true)]; // this forcibly adds it if needed
+//                if(surrogateMeta.IncludeSerializerMethod)
+//                { // don't blindly set - it might be frozen
+//                    surrogateMeta.IncludeSerializerMethod = false;
+//                }
+//                surrogateMeta.Freeze();
+//                return mt;
+//            }
+//#endif
+            return null;
+        }
+        private MetaType Create(Type type)
+        {
+            ThrowIfFrozen();
+            return new MetaType(this, type, defaultFactory);
+        }
+
+        /// <summary>
+        /// Adds support for an additional type in this model, optionally
+        /// appplying inbuilt patterns. If the type is already known to the
+        /// model, the existing type is returned **without** applying
+        /// any additional behaviour.
+        /// </summary>
+        /// <remarks>Inbuilt patterns include:
+        /// [ProtoContract]/[ProtoMember(n)]
+        /// [DataContract]/[DataMember(Order=n)]
+        /// [XmlType]/[XmlElement(Order=n)]
+        /// [On{Des|S}erializ{ing|ed}]
+        /// ShouldSerialize*/*Specified
+        /// </remarks>
+        /// <param name="type">The type to be supported</param>
+        /// <param name="applyDefaultBehaviour">Whether to apply the inbuilt configuration patterns (via attributes etc), or
+        /// just add the type with no additional configuration (the type must then be manually configured).</param>
+        /// <returns>The MetaType representing this type, allowing
+        /// further configuration.</returns>
+        public MetaType Add(Type type, bool applyDefaultBehaviour)
+        {
+            if (type == null) throw new ArgumentNullException("type");
+            MetaType newType = FindWithoutAdd(type);
+            if (newType != null) return newType; // return existing
+            int opaqueToken = 0;
+            
+#if WINRT
+            System.Reflection.TypeInfo typeInfo = System.Reflection.IntrospectionExtensions.GetTypeInfo(type);
+            if (typeInfo.IsInterface && MetaType.ienumerable.IsAssignableFrom(typeInfo)
+#else
+            if (type.IsInterface && MapType(MetaType.ienumerable).IsAssignableFrom(type)
+#endif
+                    && GetListItemType(this, type) == null)
+            {
+                throw new ArgumentException("IEnumerable[<T>] data cannot be used as a meta-type unless an Add method can be resolved");
+            }
+            try
+            {
+                newType = RecogniseCommonTypes(type);
+                if(newType != null)
+                {
+                    if(!applyDefaultBehaviour) {
+                        throw new ArgumentException(
+                            "Default behaviour must be observed for certain types with special handling; " + type.FullName,
+                            "applyDefaultBehaviour");
+                    }
+                    // we should assume that type is fully configured, though; no need to re-run:
+                    applyDefaultBehaviour = false;
+                }
+                if(newType == null) newType = Create(type);
+                newType.Pending = true;
+                TakeLock(ref opaqueToken);
+                // double checked
+                if (FindWithoutAdd(type) != null) throw new ArgumentException("Duplicate type", "type");
+                ThrowIfFrozen();
+                types.Add(newType);
+                if (applyDefaultBehaviour) { newType.ApplyDefaultBehaviour(); }
+                newType.Pending = false;
+            }
+            finally
+            {
+                ReleaseLock(opaqueToken);
+            }
+            
+            return newType;
+        }
+
+#if FEAT_COMPILER && !FX11
+        /// <summary>
+        /// Should serializers be compiled on demand? It may be useful
+        /// to disable this for debugging purposes.
+        /// </summary>
+        public bool AutoCompile
+        {
+            get { return GetOption(OPTIONS_AutoCompile); }
+            set { SetOption(OPTIONS_AutoCompile, value); }
+        }
+#endif
+        /// <summary>
+        /// Should support for unexpected types be added automatically?
+        /// If false, an exception is thrown when unexpected types
+        /// are encountered.
+        /// </summary>
+        public bool AutoAddMissingTypes
+        {
+            get { return GetOption(OPTIONS_AutoAddMissingTypes); }
+            set {
+                if (!value && GetOption(OPTIONS_IsDefaultModel))
+                {
+                    throw new InvalidOperationException("The default model must allow missing types");
+                }
+                ThrowIfFrozen();
+                SetOption(OPTIONS_AutoAddMissingTypes, value);
+            }
+        }
+        /// <summary>
+        /// Verifies that the model is still open to changes; if not, an exception is thrown
+        /// </summary>
+        private void ThrowIfFrozen()
+        {
+            if (GetOption(OPTIONS_Frozen)) throw new InvalidOperationException("The model cannot be changed once frozen");
+        }
+        /// <summary>
+        /// Prevents further changes to this model
+        /// </summary>
+        public void Freeze()
+        {
+            if (GetOption(OPTIONS_IsDefaultModel)) throw new InvalidOperationException("The default model cannot be frozen");
+            SetOption(OPTIONS_Frozen, true);
+        }
+
+        private readonly BasicList types = new BasicList();
+
+        /// <summary>
+        /// Provides the key that represents a given type in the current model.
+        /// </summary>
+        protected override int GetKeyImpl(Type type)
+        {
+            return GetKey(type, false, true);
+        }
+        internal int GetKey(Type type, bool demand, bool getBaseKey)
+        {
+            Helpers.DebugAssert(type != null);
+            try
+            {
+                int typeIndex = FindOrAddAuto(type, demand, true, false);
+                if (typeIndex >= 0)
+                {
+                    MetaType mt = (MetaType)types[typeIndex];
+                    if (getBaseKey)
+                    {
+                        mt = MetaType.GetRootType(mt);
+                        typeIndex = FindOrAddAuto(mt.Type, true, true, false);                        
+                    }
+                }
+                return typeIndex;
+            }
+            catch (NotSupportedException)
+            {
+                throw; // re-surface "as-is"
+            }
+            catch (Exception ex)
+            {
+                if (ex.Message.IndexOf(type.FullName) >= 0) throw;  // already enough info
+                throw new ProtoException(ex.Message + " (" + type.FullName + ")", ex);
+            }
+        }
+        /// <summary>
+        /// Writes a protocol-buffer representation of the given instance to the supplied stream.
+        /// </summary>
+        /// <param name="key">Represents the type (including inheritance) to consider.</param>
+        /// <param name="value">The existing instance to be serialized (cannot be null).</param>
+        /// <param name="dest">The destination stream to write to.</param>
+        protected internal override void Serialize(int key, object value, ProtoWriter dest)
+        {
+#if FEAT_IKVM
+            throw new NotSupportedException();
+#else
+            //Helpers.DebugWriteLine("Serialize", value);
+            ((MetaType)types[key]).Serializer.Write(value, dest);
+#endif
+        }
+        /// <summary>
+        /// Applies a protocol-buffer stream to an existing instance (which may be null).
+        /// </summary>
+        /// <param name="key">Represents the type (including inheritance) to consider.</param>
+        /// <param name="value">The existing instance to be modified (can be null).</param>
+        /// <param name="source">The binary stream to apply to the instance (cannot be null).</param>
+        /// <returns>The updated instance; this may be different to the instance argument if
+        /// either the original instance was null, or the stream defines a known sub-type of the
+        /// original instance.</returns>
+        protected internal override object Deserialize(int key, object value, ProtoReader source)
+        {
+#if FEAT_IKVM
+            throw new NotSupportedException();
+#else
+            //Helpers.DebugWriteLine("Deserialize", value);
+            IProtoSerializer ser = ((MetaType)types[key]).Serializer;
+            if (value == null && Helpers.IsValueType(ser.ExpectedType)) {
+                if(ser.RequiresOldValue) value = Activator.CreateInstance(ser.ExpectedType);
+                return ser.Read(value, source);
+            } else {
+                return ser.Read(value, source);
+            }
+#endif
+        }
+
+#if FEAT_COMPILER
+        // this is used by some unit-tests; do not remove
+        internal Compiler.ProtoSerializer GetSerializer(IProtoSerializer serializer, bool compiled)
+        {
+#if FEAT_IKVM
+            throw new NotSupportedException();
+#else
+            if (serializer == null) throw new ArgumentNullException("serializer");
+#if FEAT_COMPILER && !FX11
+            if (compiled) return Compiler.CompilerContext.BuildSerializer(serializer, this);
+#endif
+            return new Compiler.ProtoSerializer(serializer.Write);
+#endif
+        }
+
+#if !FX11
+        /// <summary>
+        /// Compiles the serializers individually; this is *not* a full
+        /// standalone compile, but can significantly boost performance
+        /// while allowing additional types to be added.
+        /// </summary>
+        /// <remarks>An in-place compile can access non-public types / members</remarks>
+        public void CompileInPlace()
+        {
+            foreach (MetaType type in types)
+            {
+                type.CompileInPlace();
+            }
+        }
+#endif
+#endif
+        //internal override IProtoSerializer GetTypeSerializer(Type type)
+        //{   // this list is thread-safe for reading
+        //    .Serializer;
+        //}
+        //internal override IProtoSerializer GetTypeSerializer(int key)
+        //{   // this list is thread-safe for reading
+        //    MetaType type = (MetaType)types.TryGet(key);
+        //    if (type != null) return type.Serializer;
+        //    throw new KeyNotFoundException();
+
+        //}
+
+        
+#if FEAT_COMPILER
+        private void BuildAllSerializers()
+        {
+            // note that types.Count may increase during this operation, as some serializers
+            // bring other types into play
+            for (int i = 0; i < types.Count; i++)
+            {
+                // the primary purpose of this is to force the creation of the Serializer
+                MetaType mt = (MetaType)types[i];
+                if (mt.Serializer == null)
+                    throw new InvalidOperationException("No serializer available for " + mt.Type.Name);
+            }
+        }
+#if !SILVERLIGHT
+        internal sealed class SerializerPair : IComparable
+        {
+            int IComparable.CompareTo(object obj)
+            {
+                if (obj == null) throw new ArgumentException("obj");
+                SerializerPair other = (SerializerPair)obj;
+
+                // we want to bunch all the items with the same base-type together, but we need the items with a
+                // different base **first**.
+                if (this.BaseKey == this.MetaKey)
+                {
+                    if (other.BaseKey == other.MetaKey)
+                    { // neither is a subclass
+                        return this.MetaKey.CompareTo(other.MetaKey);
+                    }
+                    else
+                    { // "other" (only) is involved in inheritance; "other" should be first
+                        return 1;
+                    }
+                }
+                else
+                {
+                    if (other.BaseKey == other.MetaKey)
+                    { // "this" (only) is involved in inheritance; "this" should be first
+                        return -1;
+                    }
+                    else
+                    { // both are involved in inheritance
+                        int result = this.BaseKey.CompareTo(other.BaseKey);
+                        if (result == 0) result = this.MetaKey.CompareTo(other.MetaKey);
+                        return result;
+                    }
+                }
+            }
+            public readonly int MetaKey, BaseKey;
+            public readonly MetaType Type;
+            public readonly MethodBuilder Serialize, Deserialize;
+            public readonly ILGenerator SerializeBody, DeserializeBody;
+            public SerializerPair(int metaKey, int baseKey, MetaType type, MethodBuilder serialize, MethodBuilder deserialize,
+                ILGenerator serializeBody, ILGenerator deserializeBody)
+            {
+                this.MetaKey = metaKey;
+                this.BaseKey = baseKey;
+                this.Serialize = serialize;
+                this.Deserialize = deserialize;
+                this.SerializeBody = serializeBody;
+                this.DeserializeBody = deserializeBody;
+                this.Type = type;
+            }
+        }
+
+        /// <summary>
+        /// Fully compiles the current model into a static-compiled model instance
+        /// </summary>
+        /// <remarks>A full compilation is restricted to accessing public types / members</remarks>
+        /// <returns>An instance of the newly created compiled type-model</returns>
+        public TypeModel Compile()
+        {
+            return Compile(null, null);
+        }
+        static ILGenerator Override(TypeBuilder type, string name)
+        {
+            MethodInfo baseMethod = type.BaseType.GetMethod(name, BindingFlags.NonPublic | BindingFlags.Instance);
+
+            ParameterInfo[] parameters = baseMethod.GetParameters();
+            Type[] paramTypes = new Type[parameters.Length];
+            for(int i = 0 ; i < paramTypes.Length ; i++) {
+                paramTypes[i] = parameters[i].ParameterType;
+            }
+            MethodBuilder newMethod = type.DefineMethod(baseMethod.Name,
+                (baseMethod.Attributes & ~MethodAttributes.Abstract) | MethodAttributes.Final, baseMethod.CallingConvention, baseMethod.ReturnType, paramTypes);
+            ILGenerator il = newMethod.GetILGenerator();
+            type.DefineMethodOverride(newMethod, baseMethod);
+            return il;
+        }
+
+#if FEAT_IKVM
+        /// <summary>
+        /// Inspect the model, and resolve all related types
+        /// </summary>
+        public void Cascade()
+        {
+            BuildAllSerializers();
+        }
+        /// <summary>
+        /// Translate a System.Type into the universe's type representation
+        /// </summary>
+        protected internal override Type MapType(System.Type type, bool demand)
+        {
+            if (type == null) return null;
+#if DEBUG
+            if (type.Assembly == typeof(IKVM.Reflection.Type).Assembly)
+            {
+                throw new InvalidOperationException(string.Format(
+                    "Somebody is passing me IKVM types! {0} should be fully-qualified at the call-site",
+                    type.Name));
+            }
+#endif
+            Type result = universe.GetType(type.AssemblyQualifiedName);
+            
+            if(result == null)
+            {
+                // things also tend to move around... *a lot* - especially in WinRT; search all as a fallback strategy
+                foreach (Assembly a in universe.GetAssemblies())
+                {
+                    result = a.GetType(type.FullName);
+                    if (result != null) break;
+                }
+                if (result == null && demand)
+                {
+                    throw new InvalidOperationException("Unable to map type: " + type.AssemblyQualifiedName);
+                }
+            }
+            return result;
+        }
+#endif
+        /// <summary>
+        /// Represents configuration options for compiling a model to 
+        /// a standalone assembly.
+        /// </summary>
+        public sealed class CompilerOptions
+        {
+            /// <summary>
+            /// Import framework options from an existing type
+            /// </summary>
+            public void SetFrameworkOptions(MetaType from)
+            {
+                if (from == null) throw new ArgumentNullException("from");
+                AttributeMap[] attribs = AttributeMap.Create(from.Model, from.Type.Assembly);
+                foreach (AttributeMap attrib in attribs)
+                {
+                    if (attrib.AttributeType.FullName == "System.Runtime.Versioning.TargetFrameworkAttribute")
+                    {
+                        object tmp;
+                        if (attrib.TryGet("FrameworkName", out tmp)) TargetFrameworkName = (string)tmp;
+                        if (attrib.TryGet("FrameworkDisplayName", out tmp)) TargetFrameworkDisplayName = (string)tmp;
+                        break;
+                    }
+                }
+            }
+
+            private string targetFrameworkName, targetFrameworkDisplayName, typeName, outputPath, imageRuntimeVersion;
+            private int metaDataVersion;
+            /// <summary>
+            /// The TargetFrameworkAttribute FrameworkName value to burn into the generated assembly
+            /// </summary>
+            public string TargetFrameworkName { get { return targetFrameworkName; } set { targetFrameworkName = value; } }
+
+            /// <summary>
+            /// The TargetFrameworkAttribute FrameworkDisplayName value to burn into the generated assembly
+            /// </summary>
+            public string TargetFrameworkDisplayName { get { return targetFrameworkDisplayName; } set { targetFrameworkDisplayName = value; } }
+            /// <summary>
+            /// The name of the TypeModel class to create
+            /// </summary>
+            public string TypeName { get { return typeName; } set { typeName = value; } }
+            /// <summary>
+            /// The path for the new dll
+            /// </summary>
+            public string OutputPath { get { return outputPath; } set { outputPath = value; } }
+            /// <summary>
+            /// The runtime version for the generated assembly
+            /// </summary>
+            public string ImageRuntimeVersion { get { return imageRuntimeVersion; } set { imageRuntimeVersion = value; } }
+            /// <summary>
+            /// The runtime version for the generated assembly
+            /// </summary>
+            public int MetaDataVersion { get { return metaDataVersion; } set { metaDataVersion = value; } }
+
+
+            private Accessibility accessibility = Accessibility.Public;
+            /// <summary>
+            /// The acecssibility of the generated serializer
+            /// </summary>
+            public Accessibility Accessibility { get { return accessibility; } set { accessibility = value; } }
+
+#if FEAT_IKVM
+            /// <summary>
+            /// The name of the container that holds the key pair.
+            /// </summary>
+            public string KeyContainer { get; set; }
+            /// <summary>
+            /// The path to a file that hold the key pair.
+            /// </summary>
+            public string KeyFile { get; set; }
+
+            /// <summary>
+            /// The public  key to sign the file with.
+            /// </summary>
+            public string PublicKey { get; set; }
+#endif
+        }
+        /// <summary>
+        /// Type accessibility
+        /// </summary>
+        public enum Accessibility
+        {
+            /// <summary>
+            /// Available to all callers
+            /// </summary>
+            Public,
+            /// <summary>
+            /// Available to all callers in the same assembly, or assemblies specified via [InternalsVisibleTo(...)]
+            /// </summary>
+            Internal
+        }
+        /// <summary>
+        /// Fully compiles the current model into a static-compiled serialization dll
+        /// (the serialization dll still requires protobuf-net for support services).
+        /// </summary>
+        /// <remarks>A full compilation is restricted to accessing public types / members</remarks>
+        /// <param name="name">The name of the TypeModel class to create</param>
+        /// <param name="path">The path for the new dll</param>
+        /// <returns>An instance of the newly created compiled type-model</returns>
+        public TypeModel Compile(string name, string path)
+        {
+            CompilerOptions options = new CompilerOptions();
+            options.TypeName = name;
+            options.OutputPath = path;
+            return Compile(options);
+        }
+
+        /// <summary>
+        /// Fully compiles the current model into a static-compiled serialization dll
+        /// (the serialization dll still requires protobuf-net for support services).
+        /// </summary>
+        /// <remarks>A full compilation is restricted to accessing public types / members</remarks>
+        /// <returns>An instance of the newly created compiled type-model</returns>
+        public TypeModel Compile(CompilerOptions options)
+        {
+            if (options == null) throw new ArgumentNullException("options");
+            string typeName = options.TypeName;
+            string path = options.OutputPath;
+            BuildAllSerializers();
+            Freeze();
+            bool save = !Helpers.IsNullOrEmpty(path);
+            if (Helpers.IsNullOrEmpty(typeName))
+            {
+                if (save) throw new ArgumentNullException("typeName");
+                typeName = Guid.NewGuid().ToString();
+            }
+
+
+            string assemblyName, moduleName;
+            if(path == null)
+            {
+                assemblyName = typeName;
+                moduleName = assemblyName + ".dll";
+            }
+            else
+            {
+                assemblyName = new System.IO.FileInfo(System.IO.Path.GetFileNameWithoutExtension(path)).Name;
+                moduleName = assemblyName + System.IO.Path.GetExtension(path);
+            }
+
+#if FEAT_IKVM
+            IKVM.Reflection.AssemblyName an = new IKVM.Reflection.AssemblyName();
+            an.Name = assemblyName;
+            AssemblyBuilder asm = universe.DefineDynamicAssembly(an, AssemblyBuilderAccess.Save);
+            if (!Helpers.IsNullOrEmpty(options.KeyFile))
+            {
+                asm.__SetAssemblyKeyPair(new StrongNameKeyPair(File.OpenRead(options.KeyFile)));
+            }
+            else if (!Helpers.IsNullOrEmpty(options.KeyContainer))
+            {
+                asm.__SetAssemblyKeyPair(new StrongNameKeyPair(options.KeyContainer));
+            }
+            else if (!Helpers.IsNullOrEmpty(options.PublicKey))
+            {
+                asm.__SetAssemblyPublicKey(FromHex(options.PublicKey));
+            }
+            if(!Helpers.IsNullOrEmpty(options.ImageRuntimeVersion) && options.MetaDataVersion != 0)
+            {
+                asm.__SetImageRuntimeVersion(options.ImageRuntimeVersion, options.MetaDataVersion);
+            }
+            ModuleBuilder module = asm.DefineDynamicModule(moduleName, path);
+#else
+            AssemblyName an = new AssemblyName();
+            an.Name = assemblyName;
+            AssemblyBuilder asm = AppDomain.CurrentDomain.DefineDynamicAssembly(an,
+                (save ? AssemblyBuilderAccess.RunAndSave : AssemblyBuilderAccess.Run)
+                );
+            ModuleBuilder module = save ? asm.DefineDynamicModule(moduleName, path)
+                                        : asm.DefineDynamicModule(moduleName);
+#endif
+
+            WriteAssemblyAttributes(options, assemblyName, asm);
+
+            TypeBuilder type = WriteBasicTypeModel(options, typeName, module);
+
+            int index;
+            bool hasInheritance;
+            SerializerPair[] methodPairs;
+            Compiler.CompilerContext.ILVersion ilVersion;
+            WriteSerializers(options, assemblyName, type, out index, out hasInheritance, out methodPairs, out ilVersion);
+
+            ILGenerator il;
+            int knownTypesCategory;
+            FieldBuilder knownTypes;
+            Type knownTypesLookupType;
+            WriteGetKeyImpl(type, hasInheritance, methodPairs, ilVersion, assemblyName, out il, out knownTypesCategory, out knownTypes, out knownTypesLookupType);
+
+            Compiler.CompilerContext ctx = WriteSerializeDeserialize(assemblyName, type, methodPairs, ilVersion, ref il);
+
+            WriteConstructors(type, ref index, methodPairs, ref il, knownTypesCategory, knownTypes, knownTypesLookupType, ctx);
+            
+
+
+            Type finalType = type.CreateType();
+            if(!Helpers.IsNullOrEmpty(path))
+            {
+                asm.Save(path);
+                Helpers.DebugWriteLine("Wrote dll:" + path);
+            }
+#if FEAT_IKVM
+            return null;
+#else
+            return (TypeModel)Activator.CreateInstance(finalType);
+#endif
+        }
+#if FEAT_IKVM
+        private byte[] FromHex(string value)
+        {
+            if (Helpers.IsNullOrEmpty(value)) throw new ArgumentNullException("value");
+            int len = value.Length / 2;
+            byte[] result = new byte[len];
+            for(int i = 0 ; i < len ; i++)
+            {
+                result[i] = Convert.ToByte(value.Substring(i * 2, 2), 16);
+            }
+            return result;
+        }
+#endif
+        private void WriteConstructors(TypeBuilder type, ref int index, SerializerPair[] methodPairs, ref ILGenerator il, int knownTypesCategory, FieldBuilder knownTypes, Type knownTypesLookupType, Compiler.CompilerContext ctx)
+        {
+            type.DefineDefaultConstructor(MethodAttributes.Public);
+            il = type.DefineTypeInitializer().GetILGenerator();
+            switch (knownTypesCategory)
+            {
+                case KnownTypes_Array:
+                    {
+                        Compiler.CompilerContext.LoadValue(il, types.Count);
+                        il.Emit(OpCodes.Newarr, ctx.MapType(typeof(System.Type)));
+                        index = 0;
+                        foreach (SerializerPair pair in methodPairs)
+                        {
+                            il.Emit(OpCodes.Dup);
+                            Compiler.CompilerContext.LoadValue(il, index);
+                            il.Emit(OpCodes.Ldtoken, pair.Type.Type);
+                            il.EmitCall(OpCodes.Call, ctx.MapType(typeof(System.Type)).GetMethod("GetTypeFromHandle"), null);
+                            il.Emit(OpCodes.Stelem_Ref);
+                            index++;
+                        }
+                        il.Emit(OpCodes.Stsfld, knownTypes);
+                        il.Emit(OpCodes.Ret);
+                    }
+                    break;
+                case KnownTypes_Dictionary:
+                    {
+                        Compiler.CompilerContext.LoadValue(il, types.Count);
+                        //LocalBuilder loc = il.DeclareLocal(knownTypesLookupType);
+                        il.Emit(OpCodes.Newobj, knownTypesLookupType.GetConstructor(new Type[] { MapType(typeof(int)) }));
+                        il.Emit(OpCodes.Stsfld, knownTypes);
+                        int typeIndex = 0;
+                        foreach (SerializerPair pair in methodPairs)
+                        {
+                            il.Emit(OpCodes.Ldsfld, knownTypes);
+                            il.Emit(OpCodes.Ldtoken, pair.Type.Type);
+                            il.EmitCall(OpCodes.Call, ctx.MapType(typeof(System.Type)).GetMethod("GetTypeFromHandle"), null);
+                            int keyIndex = typeIndex++, lastKey = pair.BaseKey;
+                            if (lastKey != pair.MetaKey) // not a base-type; need to give the index of the base-type
+                            {
+                                keyIndex = -1; // assume epic fail
+                                for (int j = 0; j < methodPairs.Length; j++)
+                                {
+                                    if (methodPairs[j].BaseKey == lastKey && methodPairs[j].MetaKey == lastKey)
+                                    {
+                                        keyIndex = j;
+                                        break;
+                                    }
+                                }
+                            }
+                            Compiler.CompilerContext.LoadValue(il, keyIndex);
+                            il.EmitCall(OpCodes.Callvirt, knownTypesLookupType.GetMethod("Add", new Type[] { MapType(typeof(System.Type)), MapType(typeof(int)) }), null);
+                        }
+                        il.Emit(OpCodes.Ret);
+                    }
+                    break;
+                case KnownTypes_Hashtable:
+                    {
+                        Compiler.CompilerContext.LoadValue(il, types.Count);
+                        il.Emit(OpCodes.Newobj, knownTypesLookupType.GetConstructor(new Type[] { MapType(typeof(int)) }));
+                        il.Emit(OpCodes.Stsfld, knownTypes);
+                        int typeIndex = 0;
+                        foreach (SerializerPair pair in methodPairs)
+                        {
+                            il.Emit(OpCodes.Ldsfld, knownTypes);
+                            il.Emit(OpCodes.Ldtoken, pair.Type.Type);
+                            il.EmitCall(OpCodes.Call, ctx.MapType(typeof(System.Type)).GetMethod("GetTypeFromHandle"), null);
+                            int keyIndex = typeIndex++, lastKey = pair.BaseKey;
+                            if (lastKey != pair.MetaKey) // not a base-type; need to give the index of the base-type
+                            {
+                                keyIndex = -1; // assume epic fail
+                                for (int j = 0; j < methodPairs.Length; j++)
+                                {
+                                    if (methodPairs[j].BaseKey == lastKey && methodPairs[j].MetaKey == lastKey)
+                                    {
+                                        keyIndex = j;
+                                        break;
+                                    }
+                                }
+                            }
+                            Compiler.CompilerContext.LoadValue(il, keyIndex);
+                            il.Emit(OpCodes.Box, MapType(typeof(int)));
+                            il.EmitCall(OpCodes.Callvirt, knownTypesLookupType.GetMethod("Add", new Type[] { MapType(typeof(object)), MapType(typeof(object)) }), null);
+                        }
+                        il.Emit(OpCodes.Ret);
+                    }
+                    break;
+                default:
+                    throw new InvalidOperationException();
+            }
+        }
+
+        private Compiler.CompilerContext WriteSerializeDeserialize(string assemblyName, TypeBuilder type, SerializerPair[] methodPairs, Compiler.CompilerContext.ILVersion ilVersion, ref ILGenerator il)
+        {
+            il = Override(type, "Serialize");
+            Compiler.CompilerContext ctx = new Compiler.CompilerContext(il, false, true, methodPairs, this, ilVersion, assemblyName, MapType(typeof(object)));
+            // arg0 = this, arg1 = key, arg2=obj, arg3=dest
+            Compiler.CodeLabel[] jumpTable = new Compiler.CodeLabel[types.Count];
+            for (int i = 0; i < jumpTable.Length; i++)
+            {
+                jumpTable[i] = ctx.DefineLabel();
+            }
+            il.Emit(OpCodes.Ldarg_1);
+            ctx.Switch(jumpTable);
+            ctx.Return();
+            for (int i = 0; i < jumpTable.Length; i++)
+            {
+                SerializerPair pair = methodPairs[i];
+                ctx.MarkLabel(jumpTable[i]);
+                il.Emit(OpCodes.Ldarg_2);
+                ctx.CastFromObject(pair.Type.Type);
+                il.Emit(OpCodes.Ldarg_3);
+                il.EmitCall(OpCodes.Call, pair.Serialize, null);
+                ctx.Return();
+            }
+
+            il = Override(type, "Deserialize");
+            ctx = new Compiler.CompilerContext(il, false, false, methodPairs, this, ilVersion, assemblyName, MapType(typeof(object)));
+            // arg0 = this, arg1 = key, arg2=obj, arg3=source
+            for (int i = 0; i < jumpTable.Length; i++)
+            {
+                jumpTable[i] = ctx.DefineLabel();
+            }
+            il.Emit(OpCodes.Ldarg_1);
+            ctx.Switch(jumpTable);
+            ctx.LoadNullRef();
+            ctx.Return();
+            for (int i = 0; i < jumpTable.Length; i++)
+            {
+                SerializerPair pair = methodPairs[i];
+                ctx.MarkLabel(jumpTable[i]);
+                Type keyType = pair.Type.Type;
+                if (keyType.IsValueType)
+                {
+                    il.Emit(OpCodes.Ldarg_2);
+                    il.Emit(OpCodes.Ldarg_3);
+                    il.EmitCall(OpCodes.Call, EmitBoxedSerializer(type, i, keyType, methodPairs, this, ilVersion, assemblyName), null);
+                    ctx.Return();
+                }
+                else
+                {
+                    il.Emit(OpCodes.Ldarg_2);
+                    ctx.CastFromObject(keyType);
+                    il.Emit(OpCodes.Ldarg_3);
+                    il.EmitCall(OpCodes.Call, pair.Deserialize, null);
+                    ctx.Return();
+                }
+            }
+            return ctx;
+        }
+
+        private const int KnownTypes_Array = 1, KnownTypes_Dictionary = 2, KnownTypes_Hashtable = 3, KnownTypes_ArrayCutoff = 20;
+        private void WriteGetKeyImpl(TypeBuilder type, bool hasInheritance, SerializerPair[] methodPairs, Compiler.CompilerContext.ILVersion ilVersion, string assemblyName, out ILGenerator il, out int knownTypesCategory, out FieldBuilder knownTypes, out Type knownTypesLookupType)
+        {
+
+            il = Override(type, "GetKeyImpl");
+            Compiler.CompilerContext ctx = new Compiler.CompilerContext(il, false, false, methodPairs, this, ilVersion, assemblyName, MapType(typeof(System.Type), true));
+            
+            if (types.Count <= KnownTypes_ArrayCutoff)
+            {
+                knownTypesCategory = KnownTypes_Array;
+                knownTypesLookupType = MapType(typeof(System.Type[]), true);
+            }
+            else
+            {
+#if NO_GENERICS
+                knownTypesLookupType = null;
+#else
+                knownTypesLookupType = MapType(typeof(System.Collections.Generic.Dictionary<System.Type, int>), false);
+#endif
+                if (knownTypesLookupType == null)
+                {
+                    knownTypesLookupType = MapType(typeof(Hashtable), true);
+                    knownTypesCategory = KnownTypes_Hashtable;
+                }
+                else
+                {
+                    knownTypesCategory = KnownTypes_Dictionary;
+                }
+            }
+            knownTypes = type.DefineField("knownTypes", knownTypesLookupType, FieldAttributes.Private | FieldAttributes.InitOnly | FieldAttributes.Static);
+
+            switch (knownTypesCategory)
+            {
+                case KnownTypes_Array:
+                    {
+                        il.Emit(OpCodes.Ldsfld, knownTypes);
+                        il.Emit(OpCodes.Ldarg_1);
+                        // note that Array.IndexOf is not supported under CF
+                        il.EmitCall(OpCodes.Callvirt, MapType(typeof(IList)).GetMethod(
+                            "IndexOf", new Type[] { MapType(typeof(object)) }), null);
+                        if (hasInheritance)
+                        {
+                            il.DeclareLocal(MapType(typeof(int))); // loc-0
+                            il.Emit(OpCodes.Dup);
+                            il.Emit(OpCodes.Stloc_0);
+
+                            BasicList getKeyLabels = new BasicList();
+                            int lastKey = -1;
+                            for (int i = 0; i < methodPairs.Length; i++)
+                            {
+                                if (methodPairs[i].MetaKey == methodPairs[i].BaseKey) break;
+                                if (lastKey == methodPairs[i].BaseKey)
+                                {   // add the last label again
+                                    getKeyLabels.Add(getKeyLabels[getKeyLabels.Count - 1]);
+                                }
+                                else
+                                {   // add a new unique label
+                                    getKeyLabels.Add(ctx.DefineLabel());
+                                    lastKey = methodPairs[i].BaseKey;
+                                }
+                            }
+                            Compiler.CodeLabel[] subtypeLabels = new Compiler.CodeLabel[getKeyLabels.Count];
+                            getKeyLabels.CopyTo(subtypeLabels, 0);
+
+                            ctx.Switch(subtypeLabels);
+                            il.Emit(OpCodes.Ldloc_0); // not a sub-type; use the original value
+                            il.Emit(OpCodes.Ret);
+
+                            lastKey = -1;
+                            // now output the different branches per sub-type (not derived type)
+                            for (int i = subtypeLabels.Length - 1; i >= 0; i--)
+                            {
+                                if (lastKey != methodPairs[i].BaseKey)
+                                {
+                                    lastKey = methodPairs[i].BaseKey;
+                                    // find the actual base-index for this base-key (i.e. the index of
+                                    // the base-type)
+                                    int keyIndex = -1;
+                                    for (int j = subtypeLabels.Length; j < methodPairs.Length; j++)
+                                    {
+                                        if (methodPairs[j].BaseKey == lastKey && methodPairs[j].MetaKey == lastKey)
+                                        {
+                                            keyIndex = j;
+                                            break;
+                                        }
+                                    }
+                                    ctx.MarkLabel(subtypeLabels[i]);
+                                    Compiler.CompilerContext.LoadValue(il, keyIndex);
+                                    il.Emit(OpCodes.Ret);
+                                }
+                            }
+                        }
+                        else
+                        {
+                            il.Emit(OpCodes.Ret);
+                        }
+                    }
+                    break;
+                case KnownTypes_Dictionary:
+                    {
+                        LocalBuilder result = il.DeclareLocal(MapType(typeof(int)));
+                        Label otherwise = il.DefineLabel();
+                        il.Emit(OpCodes.Ldsfld, knownTypes);
+                        il.Emit(OpCodes.Ldarg_1);
+                        il.Emit(OpCodes.Ldloca_S, result);
+                        il.EmitCall(OpCodes.Callvirt, knownTypesLookupType.GetMethod("TryGetValue", BindingFlags.Instance | BindingFlags.Public), null);
+                        il.Emit(OpCodes.Brfalse_S, otherwise);
+                        il.Emit(OpCodes.Ldloc_S, result);
+                        il.Emit(OpCodes.Ret);
+                        il.MarkLabel(otherwise);
+                        il.Emit(OpCodes.Ldc_I4_M1);
+                        il.Emit(OpCodes.Ret);
+                    }
+                    break;
+                case KnownTypes_Hashtable:
+                    {
+                        Label otherwise = il.DefineLabel();
+                        il.Emit(OpCodes.Ldsfld, knownTypes);
+                        il.Emit(OpCodes.Ldarg_1);
+                        il.EmitCall(OpCodes.Callvirt, knownTypesLookupType.GetProperty("Item").GetGetMethod(), null);
+                        il.Emit(OpCodes.Dup);
+                        il.Emit(OpCodes.Brfalse_S, otherwise);
+#if FX11
+                        il.Emit(OpCodes.Unbox, MapType(typeof(int)));
+                        il.Emit(OpCodes.Ldobj, MapType(typeof(int)));
+#else
+                        if (ilVersion == Compiler.CompilerContext.ILVersion.Net1)
+                        {
+                            il.Emit(OpCodes.Unbox, MapType(typeof(int)));
+                            il.Emit(OpCodes.Ldobj, MapType(typeof(int)));
+                        }
+                        else
+                        {
+                            il.Emit(OpCodes.Unbox_Any, MapType(typeof(int)));
+                        }
+#endif
+                        il.Emit(OpCodes.Ret);
+                        il.MarkLabel(otherwise);
+                        il.Emit(OpCodes.Pop);
+                        il.Emit(OpCodes.Ldc_I4_M1);
+                        il.Emit(OpCodes.Ret);
+                    }
+                    break;
+                default:
+                    throw new InvalidOperationException();
+            }
+        }
+
+        private void WriteSerializers(CompilerOptions options, string assemblyName, TypeBuilder type, out int index, out bool hasInheritance, out SerializerPair[] methodPairs, out Compiler.CompilerContext.ILVersion ilVersion)
+        {
+            Compiler.CompilerContext ctx;
+
+            index = 0;
+            hasInheritance = false;
+            methodPairs = new SerializerPair[types.Count];
+            foreach (MetaType metaType in types)
+            {
+                MethodBuilder writeMethod = type.DefineMethod("Write"
+#if DEBUG
+ + metaType.Type.Name
+#endif
+,
+                    MethodAttributes.Private | MethodAttributes.Static, CallingConventions.Standard,
+                    MapType(typeof(void)), new Type[] { metaType.Type, MapType(typeof(ProtoWriter)) });
+
+                MethodBuilder readMethod = type.DefineMethod("Read"
+#if DEBUG
+ + metaType.Type.Name
+#endif
+,
+                    MethodAttributes.Private | MethodAttributes.Static, CallingConventions.Standard,
+                    metaType.Type, new Type[] { metaType.Type, MapType(typeof(ProtoReader)) });
+
+                SerializerPair pair = new SerializerPair(
+                    GetKey(metaType.Type, true, false), GetKey(metaType.Type, true, true), metaType,
+                    writeMethod, readMethod, writeMethod.GetILGenerator(), readMethod.GetILGenerator());
+                methodPairs[index++] = pair;
+                if (pair.MetaKey != pair.BaseKey) hasInheritance = true;
+            }
+
+            if (hasInheritance)
+            {
+                Array.Sort(methodPairs);
+            }
+
+            ilVersion = Compiler.CompilerContext.ILVersion.Net2;
+            if (options.MetaDataVersion == 0x10000)
+            {
+                ilVersion = Compiler.CompilerContext.ILVersion.Net1; // old-school!
+            }
+            for (index = 0; index < methodPairs.Length; index++)
+            {
+                SerializerPair pair = methodPairs[index];
+                ctx = new Compiler.CompilerContext(pair.SerializeBody, true, true, methodPairs, this, ilVersion, assemblyName, pair.Type.Type);
+                ctx.CheckAccessibility(pair.Deserialize.ReturnType);
+                pair.Type.Serializer.EmitWrite(ctx, ctx.InputValue);
+                ctx.Return();
+
+                ctx = new Compiler.CompilerContext(pair.DeserializeBody, true, false, methodPairs, this, ilVersion, assemblyName, pair.Type.Type);
+                pair.Type.Serializer.EmitRead(ctx, ctx.InputValue);
+                if (!pair.Type.Serializer.ReturnsValue)
+                {
+                    ctx.LoadValue(ctx.InputValue);
+                }
+                ctx.Return();
+            }
+        }
+
+        private TypeBuilder WriteBasicTypeModel(CompilerOptions options, string typeName, ModuleBuilder module)
+        {
+            Type baseType = MapType(typeof(TypeModel));
+            TypeAttributes typeAttributes = (baseType.Attributes & ~TypeAttributes.Abstract) | TypeAttributes.Sealed;
+            if (options.Accessibility == Accessibility.Internal)
+            {
+                typeAttributes &= ~TypeAttributes.Public;
+            }
+
+            TypeBuilder type = module.DefineType(typeName, typeAttributes, baseType);
+            return type;
+        }
+
+        private void WriteAssemblyAttributes(CompilerOptions options, string assemblyName, AssemblyBuilder asm)
+        {
+            if (!Helpers.IsNullOrEmpty(options.TargetFrameworkName))
+            {
+                // get [TargetFramework] from mscorlib/equivalent and burn into the new assembly
+                Type versionAttribType = null;
+                try
+                { // this is best-endeavours only
+                    versionAttribType = GetType("System.Runtime.Versioning.TargetFrameworkAttribute", MapType(typeof(string)).Assembly);
+                }
+                catch { /* don't stress */ }
+                if (versionAttribType != null)
+                {
+                    PropertyInfo[] props;
+                    object[] propValues;
+                    if (Helpers.IsNullOrEmpty(options.TargetFrameworkDisplayName))
+                    {
+                        props = new PropertyInfo[0];
+                        propValues = new object[0];
+                    }
+                    else
+                    {
+                        props = new PropertyInfo[1] { versionAttribType.GetProperty("FrameworkDisplayName") };
+                        propValues = new object[1] { options.TargetFrameworkDisplayName };
+                    }
+                    CustomAttributeBuilder builder = new CustomAttributeBuilder(
+                        versionAttribType.GetConstructor(new Type[] { MapType(typeof(string)) }),
+                        new object[] { options.TargetFrameworkName },
+                        props,
+                        propValues);
+                    asm.SetCustomAttribute(builder);
+                }
+            }
+
+            // copy assembly:InternalsVisibleTo
+            Type internalsVisibleToAttribType = null;
+#if !FX11
+            try
+            {
+                internalsVisibleToAttribType = MapType(typeof(System.Runtime.CompilerServices.InternalsVisibleToAttribute));
+            }
+            catch { /* best endeavors only */ }
+#endif
+            if (internalsVisibleToAttribType != null)
+            {
+                BasicList internalAssemblies = new BasicList(), consideredAssemblies = new BasicList();
+                foreach (MetaType metaType in types)
+                {
+                    Assembly assembly = metaType.Type.Assembly;
+                    if (consideredAssemblies.IndexOfReference(assembly) >= 0) continue;
+                    consideredAssemblies.Add(assembly);
+
+                    AttributeMap[] assemblyAttribsMap = AttributeMap.Create(this, assembly);
+                    for (int i = 0; i < assemblyAttribsMap.Length; i++)
+                    {
+
+                        if (assemblyAttribsMap[i].AttributeType != internalsVisibleToAttribType) continue;
+
+                        object privelegedAssemblyObj;
+                        assemblyAttribsMap[i].TryGet("AssemblyName", out privelegedAssemblyObj);
+                        string privelegedAssemblyName = privelegedAssemblyObj as string;
+                        if (privelegedAssemblyName == assemblyName || Helpers.IsNullOrEmpty(privelegedAssemblyName)) continue; // ignore
+
+                        if (internalAssemblies.IndexOfString(privelegedAssemblyName) >= 0) continue; // seen it before
+                        internalAssemblies.Add(privelegedAssemblyName);
+
+                        CustomAttributeBuilder builder = new CustomAttributeBuilder(
+                            internalsVisibleToAttribType.GetConstructor(new Type[] { MapType(typeof(string)) }),
+                            new object[] { privelegedAssemblyName });
+                        asm.SetCustomAttribute(builder);
+                    }
+                }
+            }
+        }
+
+        private static MethodBuilder EmitBoxedSerializer(TypeBuilder type, int i, Type valueType, SerializerPair[] methodPairs, TypeModel model, Compiler.CompilerContext.ILVersion ilVersion, string assemblyName)
+        {
+            MethodInfo dedicated = methodPairs[i].Deserialize;
+            MethodBuilder boxedSerializer = type.DefineMethod("_" + i.ToString(), MethodAttributes.Static, CallingConventions.Standard,
+                model.MapType(typeof(object)), new Type[] { model.MapType(typeof(object)), model.MapType(typeof(ProtoReader)) });
+            Compiler.CompilerContext ctx = new Compiler.CompilerContext(boxedSerializer.GetILGenerator(), true, false, methodPairs, model, ilVersion, assemblyName, model.MapType(typeof(object)));
+            ctx.LoadValue(ctx.InputValue);
+            Compiler.CodeLabel @null = ctx.DefineLabel();
+            ctx.BranchIfFalse(@null, true);
+
+            Type mappedValueType = valueType;
+            ctx.LoadValue(ctx.InputValue);
+            ctx.CastFromObject(mappedValueType);
+            ctx.LoadReaderWriter();
+            ctx.EmitCall(dedicated);
+            ctx.CastToObject(mappedValueType);
+            ctx.Return();
+
+            ctx.MarkLabel(@null);
+            using (Compiler.Local typedVal = new Compiler.Local(ctx, mappedValueType))
+            {
+                // create a new valueType
+                ctx.LoadAddress(typedVal, mappedValueType);
+                ctx.EmitCtor(mappedValueType);
+                ctx.LoadValue(typedVal);
+                ctx.LoadReaderWriter();
+                ctx.EmitCall(dedicated);
+                ctx.CastToObject(mappedValueType);
+                ctx.Return();
+            }
+            return boxedSerializer;
+        }
+        
+#endif
+#endif
+        //internal bool IsDefined(Type type, int fieldNumber)
+        //{
+        //    return FindWithoutAdd(type).IsDefined(fieldNumber);
+        //}
+
+        // note that this is used by some of the unit tests
+        internal bool IsPrepared(Type type)
+        {
+            MetaType meta = FindWithoutAdd(type);
+            return meta != null && meta.IsPrepared();
+        }
+
+        internal EnumSerializer.EnumPair[] GetEnumMap(Type type)
+        {
+            int index = FindOrAddAuto(type, false, false, false);
+            return index < 0 ? null : ((MetaType)types[index]).GetEnumMap();
+        }
+
+        private int metadataTimeoutMilliseconds = 5000;
+        /// <summary>
+        /// The amount of time to wait if there are concurrent metadata access operations
+        /// </summary>
+        public int MetadataTimeoutMilliseconds
+        {
+            get { return metadataTimeoutMilliseconds; }
+            set
+            {
+                if (value <= 0) throw new ArgumentOutOfRangeException("MetadataTimeoutMilliseconds");
+                metadataTimeoutMilliseconds = value;
+            }
+        }
+
+#if DEBUG
+        int lockCount;
+        /// <summary>
+        /// Gets how many times a model lock was taken
+        /// </summary>
+        public int LockCount { get { return lockCount; } }
+#endif
+        internal void TakeLock(ref int opaqueToken)
+        {
+            const string message = "Timeout while inspecting metadata; this may indicate a deadlock. This can often be avoided by preparing necessary serializers during application initialization, rather than allowing multiple threads to perform the initial metadata inspection; please also see the LockContended event";
+            opaqueToken = 0;
+#if PORTABLE
+            if(!Monitor.TryEnter(types)) throw new TimeoutException(message); // yes, we have to do this immediately - I'm not creating a "hot" loop, just because Sleep() doesn't exist...
+            opaqueToken = Interlocked.CompareExchange(ref contentionCounter, 0, 0); // just fetch current value (starts at 1)
+#elif CF2 || CF35
+            int remaining = metadataTimeoutMilliseconds;
+            bool lockTaken;
+            do {
+                lockTaken = Monitor.TryEnter(types);
+                if(!lockTaken)
+                {
+                    if(remaining <= 0) throw new TimeoutException(message);
+                    remaining -= 50;
+                    Thread.Sleep(50);
+                }
+            } while(!lockTaken);
+            opaqueToken = Interlocked.CompareExchange(ref contentionCounter, 0, 0); // just fetch current value (starts at 1)
+#else
+            if (Monitor.TryEnter(types, metadataTimeoutMilliseconds))
+            {
+                opaqueToken = GetContention(); // just fetch current value (starts at 1)
+            }
+            else
+            {
+                AddContention();
+#if FX11
+                throw new InvalidOperationException(message);
+#else
+                throw new TimeoutException(message);
+#endif
+            }
+#endif
+
+#if DEBUG // note that here, through all code-paths: we have the lock
+            lockCount++;
+#endif
+        }
+
+        private int contentionCounter = 1;
+#if PLAT_NO_INTERLOCKED
+        private readonly object contentionLock = new object();
+#endif
+        private int GetContention()
+        {
+#if PLAT_NO_INTERLOCKED
+            lock(contentionLock)
+            {
+                return contentionCounter;
+            }
+#else
+            return Interlocked.CompareExchange(ref contentionCounter, 0, 0);
+#endif
+        }
+        private void AddContention()
+        {
+#if PLAT_NO_INTERLOCKED
+            lock(contentionLock)
+            {
+                contentionCounter++;
+            }
+#else
+            Interlocked.Increment(ref contentionCounter);
+#endif
+        }
+
+        internal void ReleaseLock(int opaqueToken)
+        {
+            if (opaqueToken != 0)
+            {
+                Monitor.Exit(types);
+                if(opaqueToken != GetContention()) // contention-count changes since we looked!
+                {
+                    LockContentedEventHandler handler = LockContended;
+                    if (handler != null)
+                    {
+                        // not hugely elegant, but this is such a far-corner-case that it doesn't need to be slick - I'll settle for cross-platform
+                        string stackTrace;
+                        try
+                        {
+                            throw new ProtoException();
+                        }
+                        catch(Exception ex)
+                        {
+                            stackTrace = ex.StackTrace;
+                        }
+                        
+                        handler(this, new LockContentedEventArgs(stackTrace));
+                    }
+                }
+            }
+        }
+        /// <summary>
+        /// If a lock-contention is detected, this event signals the *owner* of the lock responsible for the blockage, indicating
+        /// what caused the problem; this is only raised if the lock-owning code successfully completes.
+        /// </summary>
+        public event LockContentedEventHandler LockContended;
+
+        internal void ResolveListTypes(Type type, ref Type itemType, ref Type defaultType)
+        {
+            if (type == null) return;
+            if(Helpers.GetTypeCode(type) != ProtoTypeCode.Unknown) return; // don't try this[type] for inbuilts
+            if(this[type].IgnoreListHandling) return;
+
+            // handle arrays
+            if (type.IsArray)
+            {
+                if (type.GetArrayRank() != 1)
+                {
+                    throw new NotSupportedException("Multi-dimension arrays are supported");
+                }
+                itemType = type.GetElementType();
+                if (itemType == MapType(typeof(byte)))
+                {
+                    defaultType = itemType = null;
+                }
+                else
+                {
+                    defaultType = type;
+                }
+            }
+            // handle lists
+            if (itemType == null) { itemType = TypeModel.GetListItemType(this, type); }
+
+            // check for nested data (not allowed)
+            if (itemType != null)
+            {
+                Type nestedItemType = null, nestedDefaultType = null;
+                ResolveListTypes(itemType, ref nestedItemType, ref nestedDefaultType);
+                if (nestedItemType != null)
+                {
+                    throw TypeModel.CreateNestedListsNotSupported();
+                }
+            }
+
+            if (itemType != null && defaultType == null)
+            {
+#if WINRT
+                System.Reflection.TypeInfo typeInfo = System.Reflection.IntrospectionExtensions.GetTypeInfo(type);
+                if (typeInfo.IsClass && !typeInfo.IsAbstract && Helpers.GetConstructor(typeInfo, Helpers.EmptyTypes, true) != null)
+#else
+                if (type.IsClass && !type.IsAbstract && Helpers.GetConstructor(type, Helpers.EmptyTypes, true) != null)
+#endif
+                {
+                    defaultType = type;
+                }
+                if (defaultType == null)
+                {
+#if WINRT
+                    if (typeInfo.IsInterface)
+#else
+                    if (type.IsInterface)
+#endif
+                    {
+#if NO_GENERICS
+                        defaultType = typeof(ArrayList);
+#else
+                        Type[] genArgs;
+#if WINRT
+                        if (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(System.Collections.Generic.IDictionary<,>)
+                            && itemType == typeof(System.Collections.Generic.KeyValuePair<,>).MakeGenericType(genArgs = typeInfo.GenericTypeArguments))
+#else
+                        if (type.IsGenericType && type.GetGenericTypeDefinition() == MapType(typeof(System.Collections.Generic.IDictionary<,>))
+                            && itemType == MapType(typeof(System.Collections.Generic.KeyValuePair<,>)).MakeGenericType(genArgs = type.GetGenericArguments()))
+#endif
+                        {
+                            defaultType = MapType(typeof(System.Collections.Generic.Dictionary<,>)).MakeGenericType(genArgs);
+                        }
+                        else
+                        {
+                            defaultType = MapType(typeof(System.Collections.Generic.List<>)).MakeGenericType(itemType);
+                        }
+#endif
+                    }
+                }
+                // verify that the default type is appropriate
+                if (defaultType != null && !Helpers.IsAssignableFrom(type, defaultType)) { defaultType = null; }
+            }
+        }
+
+      
+#if FEAT_IKVM
+        internal override Type GetType(string fullName, Assembly context)
+        {
+            if (context != null)
+            {
+                Type found = universe.GetType(context, fullName, false);
+                if (found != null) return found;
+            }
+            return universe.GetType(fullName, false);
+        }
+#endif
+
+        internal string GetSchemaTypeName(Type effectiveType, DataFormat dataFormat, bool asReference, bool dynamicType, ref bool requiresBclImport)
+        {
+            Type tmp = Helpers.GetUnderlyingType(effectiveType);
+            if (tmp != null) effectiveType = tmp;
+
+            if (effectiveType == this.MapType(typeof(byte[]))) return "bytes";
+
+            WireType wireType;
+            IProtoSerializer ser = ValueMember.TryGetCoreSerializer(this, dataFormat, effectiveType, out wireType, false, false, false, false);
+            if (ser == null)
+            {   // model type
+                if (asReference || dynamicType)
+                {
+                    requiresBclImport = true;
+                    return "bcl.NetObjectProxy";
+                }
+                return this[effectiveType].GetSurrogateOrBaseOrSelf(true).GetSchemaTypeName();
+            }
+            else
+            {
+                if (ser is ParseableSerializer)
+                {
+                    if (asReference) requiresBclImport = true;
+                    return asReference ? "bcl.NetObjectProxy" : "string";
+                }
+
+                switch (Helpers.GetTypeCode(effectiveType))
+                {
+                    case ProtoTypeCode.Boolean: return "bool";
+                    case ProtoTypeCode.Single: return "float";
+                    case ProtoTypeCode.Double: return "double";
+                    case ProtoTypeCode.String:
+                        if (asReference) requiresBclImport = true;
+                        return asReference ? "bcl.NetObjectProxy" : "string";
+                    case ProtoTypeCode.Byte:
+                    case ProtoTypeCode.Char:
+                    case ProtoTypeCode.UInt16:
+                    case ProtoTypeCode.UInt32:
+                        switch (dataFormat)
+                        {
+                            case DataFormat.FixedSize: return "fixed32";
+                            default: return "uint32";
+                        }
+                    case ProtoTypeCode.SByte:
+                    case ProtoTypeCode.Int16:
+                    case ProtoTypeCode.Int32:
+                        switch (dataFormat)
+                        {
+                            case DataFormat.ZigZag: return "sint32";
+                            case DataFormat.FixedSize: return "sfixed32";
+                            default: return "int32";
+                        }
+                    case ProtoTypeCode.UInt64:
+                        switch (dataFormat)
+                        {
+                            case DataFormat.FixedSize: return "fixed64";
+                            default: return "uint64";
+                        }
+                    case ProtoTypeCode.Int64:
+                        switch (dataFormat)
+                        {
+                            case DataFormat.ZigZag: return "sint64";
+                            case DataFormat.FixedSize: return "sfixed64";
+                            default: return "int64";
+                        }
+                    case ProtoTypeCode.DateTime: requiresBclImport = true; return "bcl.DateTime";
+                    case ProtoTypeCode.TimeSpan: requiresBclImport = true; return "bcl.TimeSpan";
+                    case ProtoTypeCode.Decimal: requiresBclImport = true; return "bcl.Decimal";
+                    case ProtoTypeCode.Guid: requiresBclImport = true; return "bcl.Guid";
+                    default: throw new NotSupportedException("No .proto map found for: " + effectiveType.FullName);
+                }
+            }
+
+        }
+
+        /// <summary>
+        /// Designate a factory-method to use to create instances of any type; note that this only affect types seen by the serializer *after* setting the factory.
+        /// </summary>
+        public void SetDefaultFactory(MethodInfo methodInfo)
+        {
+            VerifyFactory(methodInfo, null);
+            defaultFactory = methodInfo;
+        }
+        private MethodInfo defaultFactory;
+
+        internal void VerifyFactory(MethodInfo factory, Type type)
+        {
+            if (factory != null)
+            {
+                if (type != null && Helpers.IsValueType(type)) throw new InvalidOperationException();
+                if (!factory.IsStatic) throw new ArgumentException("A factory-method must be static", "factory");
+                if ((type != null && factory.ReturnType != type) && factory.ReturnType != MapType(typeof(object))) throw new ArgumentException("The factory-method must return object" + (type == null ? "" : (" or " + type.FullName)), "factory");
+
+                if (!CallbackSet.CheckCallbackParameters(this, factory)) throw new ArgumentException("Invalid factory signature in " + factory.DeclaringType.FullName + "." + factory.Name, "factory");
+            }
+        }
+    }
+    /// <summary>
+    /// Contains the stack-trace of the owning code when a lock-contention scenario is detected
+    /// </summary>
+    public sealed class LockContentedEventArgs : EventArgs
+    {
+        private readonly string ownerStackTrace;
+        internal LockContentedEventArgs(string ownerStackTrace)
+        {
+            this.ownerStackTrace = ownerStackTrace;
+        }
+        /// <summary>
+        /// The stack-trace of the code that owned the lock when a lock-contention scenario occurred
+        /// </summary>
+        public string OwnerStackTrace { get { return ownerStackTrace; } }
+    }
+    /// <summary>
+    /// Event-type that is raised when a lock-contention scenario is detected
+    /// </summary>
+    public delegate void LockContentedEventHandler(object sender, LockContentedEventArgs args);
+
+
+}
+#endif

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/Meta/RuntimeTypeModel.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 5f9aa92f9aa952949ac0bba19f939b67
+timeCreated: 1515899112
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 82 - 0
Unity/Assets/Plugins/protobuf-net/Meta/SubType.cs

@@ -0,0 +1,82 @@
+#if !NO_RUNTIME
+using System;
+using ProtoBuf.Serializers;
+
+namespace ProtoBuf.Meta
+{
+    /// <summary>
+    /// Represents an inherited type in a type hierarchy.
+    /// </summary>
+    public sealed class SubType
+    {
+        internal sealed class Comparer : System.Collections.IComparer
+#if !NO_GENERICS
+, System.Collections.Generic.IComparer<SubType>
+#endif
+        {
+            public static readonly Comparer Default = new Comparer();
+            public int Compare(object x, object y)
+            {
+                return Compare(x as SubType, y as SubType);
+            }
+            public int Compare(SubType x, SubType y)
+            {
+                if (ReferenceEquals(x, y)) return 0;
+                if (x == null) return -1;
+                if (y == null) return 1;
+
+                return x.FieldNumber.CompareTo(y.FieldNumber);
+            }
+        }
+        private readonly int fieldNumber;
+        /// <summary>
+        /// The field-number that is used to encapsulate the data (as a nested
+        /// message) for the derived dype.
+        /// </summary>
+        public int FieldNumber { get { return fieldNumber; } }
+        /// <summary>
+        /// The sub-type to be considered.
+        /// </summary>
+        public MetaType DerivedType { get { return derivedType; } }
+        private readonly MetaType derivedType;
+
+        /// <summary>
+        /// Creates a new SubType instance.
+        /// </summary>
+        /// <param name="fieldNumber">The field-number that is used to encapsulate the data (as a nested
+        /// message) for the derived dype.</param>
+        /// <param name="derivedType">The sub-type to be considered.</param>
+        /// <param name="format">Specific encoding style to use; in particular, Grouped can be used to avoid buffering, but is not the default.</param>
+        public SubType(int fieldNumber, MetaType derivedType, DataFormat format)
+        {
+            if (derivedType == null) throw new ArgumentNullException("derivedType");
+            if (fieldNumber <= 0) throw new ArgumentOutOfRangeException("fieldNumber");
+            this.fieldNumber = fieldNumber;
+            this.derivedType = derivedType;
+            this.dataFormat = format;
+        }
+
+        private readonly DataFormat dataFormat;
+
+        private IProtoSerializer serializer;
+        internal IProtoSerializer Serializer
+        {
+            get
+            {
+                if (serializer == null) serializer = BuildSerializer();
+                return serializer;
+            }
+        }
+
+        private IProtoSerializer BuildSerializer()
+        {
+            // note the caller here is MetaType.BuildSerializer, which already has the sync-lock
+            WireType wireType = WireType.String;
+            if(dataFormat == DataFormat.Group) wireType = WireType.StartGroup; // only one exception
+            
+            IProtoSerializer ser = new SubItemSerializer(derivedType.Type, derivedType.GetKey(false, false), derivedType, false);
+            return new TagDecorator(fieldNumber, wireType, false, ser);
+        }
+    }
+}
+#endif

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/Meta/SubType.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 41873650e7e427f45bc9cee494f6bc9c
+timeCreated: 1515899112
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 62 - 0
Unity/Assets/Plugins/protobuf-net/Meta/TypeFormatEventArgs.cs

@@ -0,0 +1,62 @@
+using System;
+
+namespace ProtoBuf.Meta
+{
+    /// <summary>
+    /// Event arguments needed to perform type-formatting functions; this could be resolving a Type to a string suitable for serialization, or could
+    /// be requesting a Type from a string. If no changes are made, a default implementation will be used (from the assembly-qualified names).
+    /// </summary>
+    public class TypeFormatEventArgs : EventArgs
+    {
+        private Type type;
+        private string formattedName;
+        private readonly bool typeFixed;
+        /// <summary>
+        /// The type involved in this map; if this is initially null, a Type is expected to be provided for the string in FormattedName.
+        /// </summary>
+        public Type Type
+        {
+            get { return type; }
+            set
+            {
+                if(type != value)
+                {
+                    if (typeFixed) throw new InvalidOperationException("The type is fixed and cannot be changed");
+                    type = value;
+                }
+            }
+        }
+        /// <summary>
+        /// The formatted-name involved in this map; if this is initially null, a formatted-name is expected from the type in Type.
+        /// </summary>
+        public string FormattedName
+        {
+            get { return formattedName; }
+            set
+            {
+                if (formattedName != value)
+                {
+                    if (!typeFixed) throw new InvalidOperationException("The formatted-name is fixed and cannot be changed");
+                    formattedName = value;
+                }
+            }
+        }
+        internal TypeFormatEventArgs(string formattedName)
+        {
+            if (Helpers.IsNullOrEmpty(formattedName)) throw new ArgumentNullException("formattedName");
+            this.formattedName = formattedName;
+            // typeFixed = false; <== implicit
+        }
+        internal TypeFormatEventArgs(System.Type type)
+        {
+            if (type == null) throw new ArgumentNullException("type");
+            this.type = type;
+            typeFixed = true;
+        }
+
+    }
+    /// <summary>
+    /// Delegate type used to perform type-formatting functions; the sender originates as the type-model.
+    /// </summary>
+    public delegate void TypeFormatEventHandler(object sender, TypeFormatEventArgs args);
+}

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/Meta/TypeFormatEventArgs.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 97eec0d4199d7844b895963cf6132653
+timeCreated: 1515899113
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 1624 - 0
Unity/Assets/Plugins/protobuf-net/Meta/TypeModel.cs

@@ -0,0 +1,1624 @@
+using System;
+using System.IO;
+
+using System.Collections;
+#if FEAT_IKVM
+using Type = IKVM.Reflection.Type;
+using IKVM.Reflection;
+#else
+using System.Reflection;
+#endif
+
+namespace ProtoBuf.Meta
+{
+    /// <summary>
+    /// Provides protobuf serialization support for a number of types
+    /// </summary>
+    public abstract class TypeModel
+    {
+#if WINRT
+        internal TypeInfo MapType(TypeInfo type)
+        {
+            return type;
+        }
+#endif
+        /// <summary>
+        /// Resolve a System.Type to the compiler-specific type
+        /// </summary>
+        protected internal Type MapType(System.Type type)
+        {
+            return MapType(type, true);
+        }
+        /// <summary>
+        /// Resolve a System.Type to the compiler-specific type
+        /// </summary>
+        protected internal virtual Type MapType(System.Type type, bool demand)
+        {
+#if FEAT_IKVM
+            throw new NotImplementedException(); // this should come from RuntimeTypeModel!
+#else
+            return type;
+#endif
+        }
+        private WireType GetWireType(ProtoTypeCode code, DataFormat format, ref Type type, out int modelKey)
+        {
+            modelKey = -1;
+            if (Helpers.IsEnum(type))
+            {
+                modelKey = GetKey(ref type);
+                return WireType.Variant;
+            }
+            switch (code)
+            {
+                case ProtoTypeCode.Int64:
+                case ProtoTypeCode.UInt64:
+                    return format == DataFormat.FixedSize ? WireType.Fixed64 : WireType.Variant;
+                case ProtoTypeCode.Int16:
+                case ProtoTypeCode.Int32:
+                case ProtoTypeCode.UInt16:
+                case ProtoTypeCode.UInt32:
+                case ProtoTypeCode.Boolean:
+                case ProtoTypeCode.SByte:
+                case ProtoTypeCode.Byte:
+                case ProtoTypeCode.Char:
+                    return format == DataFormat.FixedSize ? WireType.Fixed32 : WireType.Variant;
+                case ProtoTypeCode.Double:
+                    return WireType.Fixed64;
+                case ProtoTypeCode.Single:
+                    return WireType.Fixed32;
+                case ProtoTypeCode.String:
+                case ProtoTypeCode.DateTime:
+                case ProtoTypeCode.Decimal:
+                case ProtoTypeCode.ByteArray:
+                case ProtoTypeCode.TimeSpan:
+                case ProtoTypeCode.Guid:
+                case ProtoTypeCode.Uri:
+                    return WireType.String;
+            }
+            
+            if ((modelKey = GetKey(ref type)) >= 0)
+            {
+                return WireType.String;
+            }
+            return WireType.None;
+        }
+
+#if !FEAT_IKVM
+        /// <summary>
+        /// This is the more "complete" version of Serialize, which handles single instances of mapped types.
+        /// The value is written as a complete field, including field-header and (for sub-objects) a
+        /// length-prefix
+        /// In addition to that, this provides support for:
+        ///  - basic values; individual int / string / Guid / etc
+        ///  - IEnumerable sequences of any type handled by TrySerializeAuxiliaryType
+        ///  
+        /// </summary>
+        internal bool TrySerializeAuxiliaryType(ProtoWriter writer,  Type type, DataFormat format, int tag, object value, bool isInsideList)
+        {
+            if (type == null) { type = value.GetType(); }
+
+            ProtoTypeCode typecode = Helpers.GetTypeCode(type);
+            int modelKey;
+            // note the "ref type" here normalizes against proxies
+            WireType wireType = GetWireType(typecode, format, ref type, out modelKey);
+
+
+            if (modelKey >= 0)
+            {   // write the header, but defer to the model
+                if (Helpers.IsEnum(type))
+                { // no header
+                    Serialize(modelKey, value, writer);
+                    return true;
+                }
+                else
+                {
+                    ProtoWriter.WriteFieldHeader(tag, wireType, writer);
+                    switch (wireType)
+                    {
+                        case WireType.None:
+                            throw ProtoWriter.CreateException(writer);
+                        case WireType.StartGroup:
+                        case WireType.String:
+                            // needs a wrapping length etc
+                            SubItemToken token = ProtoWriter.StartSubItem(value, writer);
+                            Serialize(modelKey, value, writer);
+                            ProtoWriter.EndSubItem(token, writer);
+                            return true;
+                        default:
+                            Serialize(modelKey, value, writer);
+                            return true;
+                    }
+                }
+            }
+            
+            if(wireType != WireType.None) {
+                ProtoWriter.WriteFieldHeader(tag, wireType, writer);
+            }
+            switch(typecode) {
+                case ProtoTypeCode.Int16: ProtoWriter.WriteInt16((short)value, writer); return true;
+                case ProtoTypeCode.Int32: ProtoWriter.WriteInt32((int)value, writer); return true;
+                case ProtoTypeCode.Int64: ProtoWriter.WriteInt64((long)value, writer); return true;
+                case ProtoTypeCode.UInt16: ProtoWriter.WriteUInt16((ushort)value, writer); return true;
+                case ProtoTypeCode.UInt32: ProtoWriter.WriteUInt32((uint)value, writer); return true;
+                case ProtoTypeCode.UInt64: ProtoWriter.WriteUInt64((ulong)value, writer); return true;
+                case ProtoTypeCode.Boolean: ProtoWriter.WriteBoolean((bool)value, writer); return true;
+                case ProtoTypeCode.SByte: ProtoWriter.WriteSByte((sbyte)value, writer); return true;
+                case ProtoTypeCode.Byte: ProtoWriter.WriteByte((byte)value, writer); return true;
+                case ProtoTypeCode.Char: ProtoWriter.WriteUInt16((ushort)(char)value, writer); return true;
+                case ProtoTypeCode.Double: ProtoWriter.WriteDouble((double)value, writer); return true;
+                case ProtoTypeCode.Single: ProtoWriter.WriteSingle((float)value, writer); return true;
+                case ProtoTypeCode.DateTime: BclHelpers.WriteDateTime((DateTime)value, writer); return true;
+                case ProtoTypeCode.Decimal: BclHelpers.WriteDecimal((decimal)value, writer); return true;
+                case ProtoTypeCode.String: ProtoWriter.WriteString((string)value, writer); return true;
+                case ProtoTypeCode.ByteArray: ProtoWriter.WriteBytes((byte[])value, writer); return true;
+                case ProtoTypeCode.TimeSpan: BclHelpers.WriteTimeSpan((TimeSpan)value, writer); return true;
+                case ProtoTypeCode.Guid: BclHelpers.WriteGuid((Guid)value, writer); return true;
+                case ProtoTypeCode.Uri: ProtoWriter.WriteString(((Uri)value).AbsoluteUri, writer); return true;
+            }
+
+            // by now, we should have covered all the simple cases; if we wrote a field-header, we have
+            // forgotten something!
+            Helpers.DebugAssert(wireType == WireType.None);
+
+            // now attempt to handle sequences (including arrays and lists)
+            IEnumerable sequence = value as IEnumerable;
+            if (sequence != null)
+            {
+                if (isInsideList) throw CreateNestedListsNotSupported();
+                foreach (object item in sequence) {
+                    if (item == null) { throw new NullReferenceException(); }
+                    if (!TrySerializeAuxiliaryType(writer, null, format, tag, item, true))
+                    {
+                        ThrowUnexpectedType(item.GetType());
+                    }
+                }
+                return true;
+            }
+            return false;
+        }
+        private void SerializeCore(ProtoWriter writer, object value)
+        {
+            if (value == null) throw new ArgumentNullException("value");
+            Type type = value.GetType();
+            int key = GetKey(ref type);
+            if (key >= 0)
+            {
+                Serialize(key, value, writer);
+            }
+            else if (!TrySerializeAuxiliaryType(writer, type, DataFormat.Default, Serializer.ListItemTag, value, false))
+            {
+                ThrowUnexpectedType(type);
+            }
+        }
+#endif
+        /// <summary>
+        /// Writes a protocol-buffer representation of the given instance to the supplied stream.
+        /// </summary>
+        /// <param name="value">The existing instance to be serialized (cannot be null).</param>
+        /// <param name="dest">The destination stream to write to.</param>
+        public void Serialize(Stream dest, object value)
+        {
+            Serialize(dest, value, null);
+        }
+        /// <summary>
+        /// Writes a protocol-buffer representation of the given instance to the supplied stream.
+        /// </summary>
+        /// <param name="value">The existing instance to be serialized (cannot be null).</param>
+        /// <param name="dest">The destination stream to write to.</param>
+        /// <param name="context">Additional information about this serialization operation.</param>
+        public void Serialize(Stream dest, object value, SerializationContext context)
+        {
+#if FEAT_IKVM
+            throw new NotSupportedException();
+#else
+            using (ProtoWriter writer = new ProtoWriter(dest, this, context))
+            {
+                writer.SetRootObject(value);
+                SerializeCore(writer, value);
+                writer.Close();
+            }
+#endif
+        }
+        /// <summary>
+        /// Writes a protocol-buffer representation of the given instance to the supplied writer.
+        /// </summary>
+        /// <param name="value">The existing instance to be serialized (cannot be null).</param>
+        /// <param name="dest">The destination writer to write to.</param>
+        public void Serialize(ProtoWriter dest, object value)
+        {
+#if FEAT_IKVM
+            throw new NotSupportedException();
+#else
+            if (dest == null) throw new ArgumentNullException("dest");
+            dest.CheckDepthFlushlock();
+            dest.SetRootObject(value);
+            SerializeCore(dest, value);
+            dest.CheckDepthFlushlock();
+            ProtoWriter.Flush(dest);
+#endif
+        }
+
+        /// <summary>
+        /// Applies a protocol-buffer stream to an existing instance (or null), using length-prefixed
+        /// data - useful with network IO.
+        /// </summary>
+        /// <param name="type">The type being merged.</param>
+        /// <param name="value">The existing instance to be modified (can be null).</param>
+        /// <param name="source">The binary stream to apply to the instance (cannot be null).</param>
+        /// <param name="style">How to encode the length prefix.</param>
+        /// <param name="fieldNumber">The tag used as a prefix to each record (only used with base-128 style prefixes).</param>
+        /// <returns>The updated instance; this may be different to the instance argument if
+        /// either the original instance was null, or the stream defines a known sub-type of the
+        /// original instance.</returns>
+        public object DeserializeWithLengthPrefix(Stream source, object value, Type type, PrefixStyle style, int fieldNumber)
+        {
+            int bytesRead;
+            return DeserializeWithLengthPrefix(source, value, type, style, fieldNumber, null, out bytesRead);
+        }
+
+
+        /// <summary>
+        /// Applies a protocol-buffer stream to an existing instance (or null), using length-prefixed
+        /// data - useful with network IO.
+        /// </summary>
+        /// <param name="type">The type being merged.</param>
+        /// <param name="value">The existing instance to be modified (can be null).</param>
+        /// <param name="source">The binary stream to apply to the instance (cannot be null).</param>
+        /// <param name="style">How to encode the length prefix.</param>
+        /// <param name="expectedField">The tag used as a prefix to each record (only used with base-128 style prefixes).</param>
+        /// <param name="resolver">Used to resolve types on a per-field basis.</param>
+        /// <returns>The updated instance; this may be different to the instance argument if
+        /// either the original instance was null, or the stream defines a known sub-type of the
+        /// original instance.</returns>
+        public object DeserializeWithLengthPrefix(Stream source, object value, Type type, PrefixStyle style, int expectedField, Serializer.TypeResolver resolver)
+        {
+            int bytesRead;
+            return DeserializeWithLengthPrefix(source, value, type, style, expectedField, resolver, out bytesRead);
+        }
+
+        /// <summary>
+        /// Applies a protocol-buffer stream to an existing instance (or null), using length-prefixed
+        /// data - useful with network IO.
+        /// </summary>
+        /// <param name="type">The type being merged.</param>
+        /// <param name="value">The existing instance to be modified (can be null).</param>
+        /// <param name="source">The binary stream to apply to the instance (cannot be null).</param>
+        /// <param name="style">How to encode the length prefix.</param>
+        /// <param name="expectedField">The tag used as a prefix to each record (only used with base-128 style prefixes).</param>
+        /// <param name="resolver">Used to resolve types on a per-field basis.</param>
+        /// <param name="bytesRead">Returns the number of bytes consumed by this operation (includes length-prefix overheads and any skipped data).</param>
+        /// <returns>The updated instance; this may be different to the instance argument if
+        /// either the original instance was null, or the stream defines a known sub-type of the
+        /// original instance.</returns>
+        public object DeserializeWithLengthPrefix(Stream source, object value, Type type, PrefixStyle style, int expectedField, Serializer.TypeResolver resolver, out int bytesRead)
+        {
+            bool haveObject;
+            return DeserializeWithLengthPrefix(source, value, type, style, expectedField, resolver, out bytesRead, out haveObject, null);
+        }
+
+        private object DeserializeWithLengthPrefix(Stream source, object value, Type type, PrefixStyle style, int expectedField, Serializer.TypeResolver resolver, out int bytesRead, out bool haveObject, SerializationContext context)
+        {
+#if FEAT_IKVM
+            throw new NotSupportedException();
+#else
+            haveObject = false;
+            bool skip;
+            int len;
+            int tmpBytesRead;
+            bytesRead = 0;
+            if (type == null && (style != PrefixStyle.Base128 || resolver == null))
+            {
+                throw new InvalidOperationException("A type must be provided unless base-128 prefixing is being used in combination with a resolver");
+            }
+            int actualField;
+            do
+            {
+                
+                bool expectPrefix = expectedField > 0 || resolver != null;
+                len = ProtoReader.ReadLengthPrefix(source, expectPrefix, style, out actualField, out tmpBytesRead);
+                if (tmpBytesRead == 0) return value;
+                bytesRead += tmpBytesRead;
+                if (len < 0) return value;
+
+                switch (style)
+                {
+                    case PrefixStyle.Base128:
+                        if (expectPrefix && expectedField == 0 && type == null && resolver != null)
+                        {
+                            type = resolver(actualField);
+                            skip = type == null;
+                        }
+                        else { skip = expectedField != actualField; }
+                        break;
+                    default:
+                        skip = false;
+                        break;
+                }
+
+                if (skip)
+                {
+                    if (len == int.MaxValue) throw new InvalidOperationException();
+                    ProtoReader.Seek(source, len, null);
+                    bytesRead += len;
+                }
+            } while (skip);
+
+            ProtoReader reader = null;
+            try
+            {
+                reader = ProtoReader.Create(source, this, context, len);
+                int key = GetKey(ref type);
+                if (key >= 0 && !Helpers.IsEnum(type))
+                {
+                    value = Deserialize(key, value, reader);
+                }
+                else
+                {
+                    if (!(TryDeserializeAuxiliaryType(reader, DataFormat.Default, Serializer.ListItemTag, type, ref value, true, false, true, false) || len == 0))
+                    {
+                        TypeModel.ThrowUnexpectedType(type); // throws
+                    }
+                }
+                bytesRead += reader.Position;
+                haveObject = true;
+                return value;
+            }
+            finally
+            {
+                ProtoReader.Recycle(reader);
+            }
+#endif
+        }
+        /// <summary>
+        /// Reads a sequence of consecutive length-prefixed items from a stream, using
+        /// either base-128 or fixed-length prefixes. Base-128 prefixes with a tag
+        /// are directly comparable to serializing multiple items in succession
+        /// (use the <see cref="Serializer.ListItemTag"/> tag to emulate the implicit behavior
+        /// when serializing a list/array). When a tag is
+        /// specified, any records with different tags are silently omitted. The
+        /// tag is ignored. The tag is ignores for fixed-length prefixes.
+        /// </summary>
+        /// <param name="source">The binary stream containing the serialized records.</param>
+        /// <param name="style">The prefix style used in the data.</param>
+        /// <param name="expectedField">The tag of records to return (if non-positive, then no tag is
+        /// expected and all records are returned).</param>
+        /// <param name="resolver">On a field-by-field basis, the type of object to deserialize (can be null if "type" is specified). </param>
+        /// <param name="type">The type of object to deserialize (can be null if "resolver" is specified).</param>
+        /// <returns>The sequence of deserialized objects.</returns>
+        public System.Collections.IEnumerable DeserializeItems(System.IO.Stream source, Type type, PrefixStyle style, int expectedField, Serializer.TypeResolver resolver)
+        {
+            return DeserializeItems(source, type, style, expectedField, resolver, null);
+        }
+        /// <summary>
+        /// Reads a sequence of consecutive length-prefixed items from a stream, using
+        /// either base-128 or fixed-length prefixes. Base-128 prefixes with a tag
+        /// are directly comparable to serializing multiple items in succession
+        /// (use the <see cref="Serializer.ListItemTag"/> tag to emulate the implicit behavior
+        /// when serializing a list/array). When a tag is
+        /// specified, any records with different tags are silently omitted. The
+        /// tag is ignored. The tag is ignores for fixed-length prefixes.
+        /// </summary>
+        /// <param name="source">The binary stream containing the serialized records.</param>
+        /// <param name="style">The prefix style used in the data.</param>
+        /// <param name="expectedField">The tag of records to return (if non-positive, then no tag is
+        /// expected and all records are returned).</param>
+        /// <param name="resolver">On a field-by-field basis, the type of object to deserialize (can be null if "type" is specified). </param>
+        /// <param name="type">The type of object to deserialize (can be null if "resolver" is specified).</param>
+        /// <returns>The sequence of deserialized objects.</returns>
+        /// <param name="context">Additional information about this serialization operation.</param>
+        public System.Collections.IEnumerable DeserializeItems(System.IO.Stream source, Type type, PrefixStyle style, int expectedField, Serializer.TypeResolver resolver, SerializationContext context)
+        {
+            return new DeserializeItemsIterator(this, source, type, style, expectedField, resolver, context);
+        }
+
+#if !NO_GENERICS
+        /// <summary>
+        /// Reads a sequence of consecutive length-prefixed items from a stream, using
+        /// either base-128 or fixed-length prefixes. Base-128 prefixes with a tag
+        /// are directly comparable to serializing multiple items in succession
+        /// (use the <see cref="Serializer.ListItemTag"/> tag to emulate the implicit behavior
+        /// when serializing a list/array). When a tag is
+        /// specified, any records with different tags are silently omitted. The
+        /// tag is ignored. The tag is ignores for fixed-length prefixes.
+        /// </summary>
+        /// <typeparam name="T">The type of object to deserialize.</typeparam>
+        /// <param name="source">The binary stream containing the serialized records.</param>
+        /// <param name="style">The prefix style used in the data.</param>
+        /// <param name="expectedField">The tag of records to return (if non-positive, then no tag is
+        /// expected and all records are returned).</param>
+        /// <returns>The sequence of deserialized objects.</returns>
+        public System.Collections.Generic.IEnumerable<T> DeserializeItems<T>(Stream source, PrefixStyle style, int expectedField)
+        {
+            return DeserializeItems<T>(source, style, expectedField, null);
+        }
+        /// <summary>
+        /// Reads a sequence of consecutive length-prefixed items from a stream, using
+        /// either base-128 or fixed-length prefixes. Base-128 prefixes with a tag
+        /// are directly comparable to serializing multiple items in succession
+        /// (use the <see cref="Serializer.ListItemTag"/> tag to emulate the implicit behavior
+        /// when serializing a list/array). When a tag is
+        /// specified, any records with different tags are silently omitted. The
+        /// tag is ignored. The tag is ignores for fixed-length prefixes.
+        /// </summary>
+        /// <typeparam name="T">The type of object to deserialize.</typeparam>
+        /// <param name="source">The binary stream containing the serialized records.</param>
+        /// <param name="style">The prefix style used in the data.</param>
+        /// <param name="expectedField">The tag of records to return (if non-positive, then no tag is
+        /// expected and all records are returned).</param>
+        /// <returns>The sequence of deserialized objects.</returns>
+        /// <param name="context">Additional information about this serialization operation.</param>
+        public System.Collections.Generic.IEnumerable<T> DeserializeItems<T>(Stream source, PrefixStyle style, int expectedField, SerializationContext context)
+        {
+            return new DeserializeItemsIterator<T>(this, source, style, expectedField, context);
+        }
+
+        private sealed class DeserializeItemsIterator<T> : DeserializeItemsIterator,
+            System.Collections.Generic.IEnumerator<T>,
+            System.Collections.Generic.IEnumerable<T>
+        {
+            System.Collections.Generic.IEnumerator<T> System.Collections.Generic.IEnumerable<T>.GetEnumerator() { return this; }
+            public new T Current { get { return (T)base.Current; } }
+            void IDisposable.Dispose() { }
+            public DeserializeItemsIterator(TypeModel model, Stream source, PrefixStyle style, int expectedField, SerializationContext context)
+                : base(model, source, model.MapType(typeof(T)), style, expectedField, null, context) { }
+        }
+#endif
+        private class DeserializeItemsIterator : IEnumerator, IEnumerable
+        {
+            IEnumerator IEnumerable.GetEnumerator() { return this; }
+            private bool haveObject;
+            private object current;
+            public bool MoveNext()
+            {
+                if (haveObject)
+                {
+                    int bytesRead;
+                    current = model.DeserializeWithLengthPrefix(source, null, type, style, expectedField, resolver, out bytesRead, out haveObject, context);
+                }
+                return haveObject;
+            }
+            void IEnumerator.Reset() { throw new NotSupportedException(); }
+            public object Current { get { return current; } }
+            private readonly Stream source;
+            private readonly Type type;
+            private readonly PrefixStyle style;
+            private readonly int expectedField;
+            private readonly Serializer.TypeResolver resolver;
+            private readonly TypeModel model;
+            private readonly SerializationContext context;
+            public DeserializeItemsIterator(TypeModel model, Stream source, Type type, PrefixStyle style, int expectedField, Serializer.TypeResolver resolver, SerializationContext context)
+            {
+                haveObject = true;
+                this.source = source;
+                this.type = type;
+                this.style = style;
+                this.expectedField = expectedField;
+                this.resolver = resolver;
+                this.model = model;
+                this.context = context;
+            }
+        }
+
+        /// <summary>
+        /// Writes a protocol-buffer representation of the given instance to the supplied stream,
+        /// with a length-prefix. This is useful for socket programming,
+        /// as DeserializeWithLengthPrefix can be used to read the single object back
+        /// from an ongoing stream.
+        /// </summary>
+        /// <param name="type">The type being serialized.</param>
+        /// <param name="value">The existing instance to be serialized (cannot be null).</param>
+        /// <param name="style">How to encode the length prefix.</param>
+        /// <param name="dest">The destination stream to write to.</param>
+        /// <param name="fieldNumber">The tag used as a prefix to each record (only used with base-128 style prefixes).</param>
+        public void SerializeWithLengthPrefix(Stream dest, object value, Type type, PrefixStyle style, int fieldNumber)
+        {
+            SerializeWithLengthPrefix(dest, value, type, style, fieldNumber, null);
+        }
+        /// <summary>
+        /// Writes a protocol-buffer representation of the given instance to the supplied stream,
+        /// with a length-prefix. This is useful for socket programming,
+        /// as DeserializeWithLengthPrefix can be used to read the single object back
+        /// from an ongoing stream.
+        /// </summary>
+        /// <param name="type">The type being serialized.</param>
+        /// <param name="value">The existing instance to be serialized (cannot be null).</param>
+        /// <param name="style">How to encode the length prefix.</param>
+        /// <param name="dest">The destination stream to write to.</param>
+        /// <param name="fieldNumber">The tag used as a prefix to each record (only used with base-128 style prefixes).</param>
+        /// <param name="context">Additional information about this serialization operation.</param>
+        public void SerializeWithLengthPrefix(Stream dest, object value, Type type, PrefixStyle style, int fieldNumber, SerializationContext context)
+        {
+            if (type == null)
+            {
+                if(value == null) throw new ArgumentNullException("value");
+                type = MapType(value.GetType());
+            }
+            int key = GetKey(ref type);
+            using (ProtoWriter writer = new ProtoWriter(dest, this, context))
+            {
+                switch (style)
+                {
+                    case PrefixStyle.None:
+                        Serialize(key, value, writer);
+                        break;
+                    case PrefixStyle.Base128:
+                    case PrefixStyle.Fixed32:
+                    case PrefixStyle.Fixed32BigEndian:
+                        ProtoWriter.WriteObject(value, key, writer, style, fieldNumber);
+                        break;
+                    default:
+                        throw new ArgumentOutOfRangeException("style");
+                }
+                writer.Close();
+            }
+        }
+        /// <summary>
+        /// Applies a protocol-buffer stream to an existing instance (which may be null).
+        /// </summary>
+        /// <param name="type">The type (including inheritance) to consider.</param>
+        /// <param name="value">The existing instance to be modified (can be null).</param>
+        /// <param name="source">The binary stream to apply to the instance (cannot be null).</param>
+        /// <returns>The updated instance; this may be different to the instance argument if
+        /// either the original instance was null, or the stream defines a known sub-type of the
+        /// original instance.</returns>
+        public object Deserialize(Stream source, object value, System.Type type)
+        {
+            return Deserialize(source, value, type, null);
+        }
+        /// <summary>
+        /// Applies a protocol-buffer stream to an existing instance (which may be null).
+        /// </summary>
+        /// <param name="type">The type (including inheritance) to consider.</param>
+        /// <param name="value">The existing instance to be modified (can be null).</param>
+        /// <param name="source">The binary stream to apply to the instance (cannot be null).</param>
+        /// <returns>The updated instance; this may be different to the instance argument if
+        /// either the original instance was null, or the stream defines a known sub-type of the
+        /// original instance.</returns>
+        /// <param name="context">Additional information about this serialization operation.</param>
+        public object Deserialize(Stream source, object value, System.Type type, SerializationContext context)
+        {
+#if FEAT_IKVM
+            throw new NotSupportedException();
+#else
+            bool autoCreate = PrepareDeserialize(value, ref type);
+            ProtoReader reader = null;
+            try
+            {
+                reader = ProtoReader.Create(source, this, context, ProtoReader.TO_EOF);
+                if (value != null) reader.SetRootObject(value);
+                object obj = DeserializeCore(reader, type, value, autoCreate);
+                reader.CheckFullyConsumed();
+                return obj;
+            }
+            finally
+            {
+                ProtoReader.Recycle(reader);
+            }
+#endif
+        }
+
+        private bool PrepareDeserialize(object value, ref Type type)
+        {
+            if (type == null)
+            {
+                if (value == null)
+                {
+                    throw new ArgumentNullException("type");
+                }
+                else
+                {
+                    type = MapType(value.GetType());
+                }
+            }
+            bool autoCreate = true;
+#if !NO_GENERICS
+            Type underlyingType = Helpers.GetUnderlyingType(type);
+            if (underlyingType != null)
+            {
+                type = underlyingType;
+                autoCreate = false;
+            }
+#endif
+            return autoCreate;
+        }
+
+        /// <summary>
+        /// Applies a protocol-buffer stream to an existing instance (which may be null).
+        /// </summary>
+        /// <param name="type">The type (including inheritance) to consider.</param>
+        /// <param name="value">The existing instance to be modified (can be null).</param>
+        /// <param name="source">The binary stream to apply to the instance (cannot be null).</param>
+        /// <param name="length">The number of bytes to consume.</param>
+        /// <returns>The updated instance; this may be different to the instance argument if
+        /// either the original instance was null, or the stream defines a known sub-type of the
+        /// original instance.</returns>
+        public object Deserialize(Stream source, object value, System.Type type, int length)
+        {
+            return Deserialize(source, value, type, length, null);
+        }
+        /// <summary>
+        /// Applies a protocol-buffer stream to an existing instance (which may be null).
+        /// </summary>
+        /// <param name="type">The type (including inheritance) to consider.</param>
+        /// <param name="value">The existing instance to be modified (can be null).</param>
+        /// <param name="source">The binary stream to apply to the instance (cannot be null).</param>
+        /// <param name="length">The number of bytes to consume (or -1 to read to the end of the stream).</param>
+        /// <returns>The updated instance; this may be different to the instance argument if
+        /// either the original instance was null, or the stream defines a known sub-type of the
+        /// original instance.</returns>
+        /// <param name="context">Additional information about this serialization operation.</param>
+        public object Deserialize(Stream source, object value, System.Type type, int length, SerializationContext context)
+        {
+#if FEAT_IKVM
+            throw new NotSupportedException();
+#else
+            bool autoCreate = PrepareDeserialize(value, ref type);
+            ProtoReader reader = null;
+            try
+            {
+                reader = ProtoReader.Create(source, this, context, length);
+                if (value != null) reader.SetRootObject(value);
+                object obj = DeserializeCore(reader, type, value, autoCreate);
+                reader.CheckFullyConsumed();
+                return obj;
+            }
+            finally
+            {
+                ProtoReader.Recycle(reader);
+            }
+#endif
+        }
+        /// <summary>
+        /// Applies a protocol-buffer reader to an existing instance (which may be null).
+        /// </summary>
+        /// <param name="type">The type (including inheritance) to consider.</param>
+        /// <param name="value">The existing instance to be modified (can be null).</param>
+        /// <param name="source">The reader to apply to the instance (cannot be null).</param>
+        /// <returns>The updated instance; this may be different to the instance argument if
+        /// either the original instance was null, or the stream defines a known sub-type of the
+        /// original instance.</returns>
+        public object Deserialize(ProtoReader source, object value, System.Type type)
+        {
+#if FEAT_IKVM
+            throw new NotSupportedException();
+#else
+            if (source == null) throw new ArgumentNullException("source");
+            bool autoCreate = PrepareDeserialize(value, ref type);
+            if (value != null) source.SetRootObject(value);
+            object obj = DeserializeCore(source, type, value, autoCreate);
+            source.CheckFullyConsumed();
+            return obj;
+#endif
+        }
+
+#if !FEAT_IKVM
+        private object DeserializeCore(ProtoReader reader, Type type, object value, bool noAutoCreate)
+        {
+            int key = GetKey(ref type);
+            if (key >= 0 && !Helpers.IsEnum(type))
+            {
+                return Deserialize(key, value, reader);
+            }
+            // this returns true to say we actively found something, but a value is assigned either way (or throws)
+            TryDeserializeAuxiliaryType(reader, DataFormat.Default, Serializer.ListItemTag, type, ref value, true, false, noAutoCreate, false);
+            return value;
+        }
+#endif
+#if WINRT
+        private static readonly System.Reflection.TypeInfo ilist = typeof(IList).GetTypeInfo();
+#else
+        private static readonly System.Type ilist = typeof(IList);
+#endif
+        internal static MethodInfo ResolveListAdd(TypeModel model, Type listType, Type itemType, out bool isList)
+        {
+#if WINRT
+            TypeInfo listTypeInfo = listType.GetTypeInfo();
+#else
+            Type listTypeInfo = listType;
+#endif
+            isList = model.MapType(ilist).IsAssignableFrom(listTypeInfo);
+
+            Type[] types = { itemType };
+            MethodInfo add = Helpers.GetInstanceMethod(listTypeInfo, "Add", types);
+
+#if !NO_GENERICS
+            if (add == null)
+            {   // fallback: look for ICollection<T>'s Add(typedObject) method
+
+                bool forceList = listTypeInfo.IsInterface &&
+                    listTypeInfo == model.MapType(typeof(System.Collections.Generic.IEnumerable<>)).MakeGenericType(types)
+#if WINRT
+                    .GetTypeInfo()
+#endif
+                    ;
+
+#if WINRT
+                TypeInfo constuctedListType = typeof(System.Collections.Generic.ICollection<>).MakeGenericType(types).GetTypeInfo();
+#else
+                Type constuctedListType = model.MapType(typeof(System.Collections.Generic.ICollection<>)).MakeGenericType(types);
+#endif
+                if (forceList || constuctedListType.IsAssignableFrom(listTypeInfo))
+                {
+                    add = Helpers.GetInstanceMethod(constuctedListType, "Add", types);
+                }
+            }
+
+            if (add == null)
+            {
+                
+#if WINRT
+                foreach (Type tmpType in listTypeInfo.ImplementedInterfaces)
+#else
+                foreach (Type interfaceType in listTypeInfo.GetInterfaces())
+#endif
+                {
+#if WINRT
+                    TypeInfo interfaceType = tmpType.GetTypeInfo();
+#endif
+                    if (interfaceType.Name == "IProducerConsumerCollection`1" && interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition().FullName == "System.Collections.Concurrent.IProducerConsumerCollection`1")
+                    {
+                        add = Helpers.GetInstanceMethod(interfaceType, "TryAdd", types);
+                        if (add != null) break;
+                    }
+                }
+            }
+#endif
+
+            if (add == null)
+            {   // fallback: look for a public list.Add(object) method
+                types[0] = model.MapType(typeof(object));
+                add = Helpers.GetInstanceMethod(listTypeInfo, "Add", types);
+            }
+            if (add == null && isList)
+            {   // fallback: look for IList's Add(object) method
+                add = Helpers.GetInstanceMethod(model.MapType(ilist), "Add", types);
+            }
+            return add;
+        }
+        internal static Type GetListItemType(TypeModel model, Type listType)
+        {
+            Helpers.DebugAssert(listType != null);
+
+#if WINRT
+            TypeInfo listTypeInfo = listType.GetTypeInfo();
+            if (listType == typeof(string) || listType.IsArray
+                || !typeof(IEnumerable).GetTypeInfo().IsAssignableFrom(listTypeInfo)) return null;
+#else
+            if (listType == model.MapType(typeof(string)) || listType.IsArray
+                || !model.MapType(typeof(IEnumerable)).IsAssignableFrom(listType)) return null;
+#endif
+            
+            BasicList candidates = new BasicList();
+#if WINRT
+            foreach (MethodInfo method in listType.GetRuntimeMethods())
+#else
+            foreach (MethodInfo method in listType.GetMethods())
+#endif
+            {
+                if (method.IsStatic || method.Name != "Add") continue;
+                ParameterInfo[] parameters = method.GetParameters();
+                Type paramType;
+                if (parameters.Length == 1 && !candidates.Contains(paramType = parameters[0].ParameterType))
+                {
+                    candidates.Add(paramType);
+                }
+            }
+
+            string name = listType.Name;
+            bool isQueueStack = name != null && (name.IndexOf("Queue") >= 0 || name.IndexOf("Stack") >= 0);
+#if !NO_GENERICS
+            if(!isQueueStack)
+            {
+                TestEnumerableListPatterns(model, candidates, listType);
+#if WINRT
+                foreach (Type iType in listTypeInfo.ImplementedInterfaces)
+                {
+                    TestEnumerableListPatterns(model, candidates, iType);
+                }
+#else
+                foreach (Type iType in listType.GetInterfaces())
+                {
+                    TestEnumerableListPatterns(model, candidates, iType);
+                }
+#endif
+            }
+#endif
+
+#if WINRT
+            // more convenient GetProperty overload not supported on all platforms
+            foreach (PropertyInfo indexer in listType.GetRuntimeProperties())
+            {
+                if (indexer.Name != "Item" || candidates.Contains(indexer.PropertyType)) continue;
+                ParameterInfo[] args = indexer.GetIndexParameters();
+                if (args.Length != 1 || args[0].ParameterType != typeof(int)) continue;
+                MethodInfo getter = indexer.GetMethod;
+                if (getter == null || getter.IsStatic) continue;
+                candidates.Add(indexer.PropertyType);
+            }
+#else
+            // more convenient GetProperty overload not supported on all platforms
+            foreach (PropertyInfo indexer in listType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
+            {
+                if (indexer.Name != "Item" || candidates.Contains(indexer.PropertyType)) continue;
+                ParameterInfo[] args = indexer.GetIndexParameters();
+                if (args.Length != 1 || args[0].ParameterType != model.MapType(typeof(int))) continue;
+                candidates.Add(indexer.PropertyType);
+            }
+#endif
+
+            switch (candidates.Count)
+            {
+                case 0:
+                    return null;
+                case 1:
+                    return (Type)candidates[0];
+                case 2:
+                    if (CheckDictionaryAccessors(model, (Type)candidates[0], (Type)candidates[1])) return (Type)candidates[0];
+                    if (CheckDictionaryAccessors(model, (Type)candidates[1], (Type)candidates[0])) return (Type)candidates[1];
+                    break;
+            }
+
+            return null;
+        }
+
+        private static void TestEnumerableListPatterns(TypeModel model, BasicList candidates, Type iType)
+        {
+
+#if WINRT
+            TypeInfo iTypeInfo = iType.GetTypeInfo();
+            if (iTypeInfo.IsGenericType)
+            {
+                Type typeDef = iTypeInfo.GetGenericTypeDefinition();
+                if(typeDef == typeof(System.Collections.Generic.ICollection<>) || typeDef.GetTypeInfo().FullName == "System.Collections.Concurrent.IProducerConsumerCollection`1")
+                {
+                        
+                    Type[] iTypeArgs = iTypeInfo.GenericTypeArguments;
+                    if (!candidates.Contains(iTypeArgs[0]))
+                    {
+                        candidates.Add(iTypeArgs[0]);
+                    }
+                }
+            }
+#elif !NO_GENERICS
+            if (iType.IsGenericType)
+            {
+                Type typeDef = iType.GetGenericTypeDefinition();
+                if (typeDef == model.MapType(typeof(System.Collections.Generic.IEnumerable<>))
+                    || typeDef == model.MapType(typeof(System.Collections.Generic.ICollection<>))
+                    || typeDef.FullName == "System.Collections.Concurrent.IProducerConsumerCollection`1")
+                {
+                    Type[] iTypeArgs = iType.GetGenericArguments();
+                    if (!candidates.Contains(iTypeArgs[0]))
+                    {
+                        candidates.Add(iTypeArgs[0]);
+                    }
+                }
+            }
+#endif
+        }
+
+        private static bool CheckDictionaryAccessors(TypeModel model, Type pair, Type value)
+        {
+            
+#if NO_GENERICS
+            return false;
+#elif WINRT
+            TypeInfo finalType = pair.GetTypeInfo();
+            return finalType.IsGenericType && finalType.GetGenericTypeDefinition() == typeof(System.Collections.Generic.KeyValuePair<,>)
+                && finalType.GenericTypeArguments[1] == value;
+#else
+            return pair.IsGenericType && pair.GetGenericTypeDefinition() == model.MapType(typeof(System.Collections.Generic.KeyValuePair<,>))
+                && pair.GetGenericArguments()[1] == value;
+#endif
+        }
+
+#if !FEAT_IKVM
+        private bool TryDeserializeList(TypeModel model, ProtoReader reader, DataFormat format, int tag, Type listType, Type itemType, ref object value)
+        {
+            bool isList;
+            MethodInfo addMethod = TypeModel.ResolveListAdd(model, listType, itemType, out isList);
+            if (addMethod == null) throw new NotSupportedException("Unknown list variant: " + listType.FullName);
+            bool found = false;
+            object nextItem = null;
+            IList list = value as IList;
+            object[] args = isList ? null : new object[1];
+            BasicList arraySurrogate = listType.IsArray ? new BasicList() : null;
+
+            while (TryDeserializeAuxiliaryType(reader, format, tag, itemType, ref nextItem, true, true, true, true))
+            {
+                found = true;
+                if (value == null && arraySurrogate == null)
+                {
+                    value = CreateListInstance(listType, itemType);
+                    list = value as IList;
+                }
+                if (list != null)
+                {
+                    list.Add(nextItem);
+                }
+                else if (arraySurrogate != null)
+                {
+                    arraySurrogate.Add(nextItem);
+                }
+                else
+                {
+                    args[0] = nextItem;
+                    addMethod.Invoke(value, args);
+                }
+                nextItem = null;
+            }
+            if (arraySurrogate != null)
+            {
+                Array newArray;
+                if (value != null)
+                {
+                    if (arraySurrogate.Count == 0)
+                    {   // we'll stay with what we had, thanks
+                    }
+                    else
+                    { 
+                        Array existing = (Array)value;
+                        newArray = Array.CreateInstance(itemType, existing.Length + arraySurrogate.Count);
+                        Array.Copy(existing, newArray, existing.Length);
+                        arraySurrogate.CopyTo(newArray, existing.Length);
+                        value = newArray;
+                    }
+                }
+                else
+                {
+                    newArray = Array.CreateInstance(itemType, arraySurrogate.Count);
+                    arraySurrogate.CopyTo(newArray, 0);
+                    value = newArray;
+                }
+            }
+            return found;
+        }
+
+        private static object CreateListInstance(Type listType, Type itemType)
+        {
+            Type concreteListType = listType;
+
+            if (listType.IsArray)
+            {
+                return Array.CreateInstance(itemType, 0);
+            }
+
+#if WINRT
+            TypeInfo listTypeInfo = listType.GetTypeInfo();
+            if (!listTypeInfo.IsClass || listTypeInfo.IsAbstract ||
+                Helpers.GetConstructor(listTypeInfo, Helpers.EmptyTypes, true) == null)
+#else
+            if (!listType.IsClass || listType.IsAbstract ||
+                Helpers.GetConstructor(listType, Helpers.EmptyTypes, true) == null)
+#endif
+            {
+                string fullName;
+                bool handled = false;
+#if WINRT
+                if (listTypeInfo.IsInterface &&
+#else
+                if (listType.IsInterface &&
+#endif
+                    (fullName = listType.FullName) != null && fullName.IndexOf("Dictionary") >= 0) // have to try to be frugal here...
+                {
+#if !NO_GENERICS
+#if WINRT
+                    TypeInfo finalType = listType.GetTypeInfo();
+                    if (finalType.IsGenericType && finalType.GetGenericTypeDefinition() == typeof(System.Collections.Generic.IDictionary<,>))
+                    {
+                        Type[] genericTypes = listType.GenericTypeArguments;
+                        concreteListType = typeof(System.Collections.Generic.Dictionary<,>).MakeGenericType(genericTypes);
+                        handled = true;
+                    }
+#else
+                    if (listType.IsGenericType && listType.GetGenericTypeDefinition() == typeof(System.Collections.Generic.IDictionary<,>))
+                    {
+                        Type[] genericTypes = listType.GetGenericArguments();
+                        concreteListType = typeof(System.Collections.Generic.Dictionary<,>).MakeGenericType(genericTypes);
+                        handled = true;
+                    }
+#endif
+#endif
+#if !SILVERLIGHT && !WINRT && !PORTABLE
+                    if (!handled && listType == typeof(IDictionary))
+                    {
+                        concreteListType = typeof(Hashtable);
+                        handled = true;
+                    }
+#endif
+                }
+#if !NO_GENERICS
+                if (!handled)
+                {
+                    concreteListType = typeof(System.Collections.Generic.List<>).MakeGenericType(itemType);
+                    handled = true;
+                }
+#endif
+
+#if !SILVERLIGHT && !WINRT && !PORTABLE
+                if (!handled)
+                {
+                    concreteListType = typeof(ArrayList);
+                    handled = true;
+                }
+#endif
+            }
+            return Activator.CreateInstance(concreteListType);
+        }
+
+        /// <summary>
+        /// This is the more "complete" version of Deserialize, which handles single instances of mapped types.
+        /// The value is read as a complete field, including field-header and (for sub-objects) a
+        /// length-prefix..kmc  
+        /// 
+        /// In addition to that, this provides support for:
+        ///  - basic values; individual int / string / Guid / etc
+        ///  - IList sets of any type handled by TryDeserializeAuxiliaryType
+        /// </summary>
+        internal bool TryDeserializeAuxiliaryType(ProtoReader reader, DataFormat format, int tag, Type type, ref object value, bool skipOtherFields, bool asListItem, bool autoCreate, bool insideList)
+        {
+            if (type == null) throw new ArgumentNullException("type");
+            Type itemType = null;
+            ProtoTypeCode typecode = Helpers.GetTypeCode(type);
+            int modelKey;
+            WireType wiretype = GetWireType(typecode, format, ref type, out modelKey);
+
+            bool found = false;
+            if (wiretype == WireType.None)
+            {
+                itemType = GetListItemType(this, type);
+                if (itemType == null && type.IsArray && type.GetArrayRank() == 1 && type != typeof(byte[]))
+                {
+                    itemType = type.GetElementType();
+                }
+                if (itemType != null)
+                {
+                    if (insideList) throw TypeModel.CreateNestedListsNotSupported();
+                    found = TryDeserializeList(this, reader, format, tag, type, itemType, ref value);
+                    if (!found && autoCreate)
+                    {
+                        value = CreateListInstance(type, itemType);
+                    }
+                    return found;
+                }
+
+                // otherwise, not a happy bunny...
+                ThrowUnexpectedType(type);
+            }
+            
+            // to treat correctly, should read all values
+
+            while (true)
+            {
+                // for convenience (re complex exit conditions), additional exit test here:
+                // if we've got the value, are only looking for one, and we aren't a list - then exit
+                if (found && asListItem) break;
+
+
+                // read the next item
+                int fieldNumber = reader.ReadFieldHeader();
+                if (fieldNumber <= 0) break;
+                if (fieldNumber != tag)
+                {
+                    if (skipOtherFields)
+                    {
+                        reader.SkipField();
+                        continue;
+                    }
+                    throw ProtoReader.AddErrorData(new InvalidOperationException(
+                        "Expected field " + tag.ToString() + ", but found " + fieldNumber.ToString()), reader);
+                }
+                found = true;
+                reader.Hint(wiretype); // handle signed data etc
+
+                if (modelKey >= 0)
+                {
+                    switch (wiretype)
+                    {
+                        case WireType.String:
+                        case WireType.StartGroup:
+                            SubItemToken token = ProtoReader.StartSubItem(reader);
+                            value = Deserialize(modelKey, value, reader);
+                            ProtoReader.EndSubItem(token, reader);
+                            continue;
+                        default:
+                            value = Deserialize(modelKey, value, reader);
+                            continue;
+                    }
+                }
+                switch (typecode)
+                {
+                    case ProtoTypeCode.Int16: value = reader.ReadInt16(); continue;
+                    case ProtoTypeCode.Int32: value = reader.ReadInt32(); continue;
+                    case ProtoTypeCode.Int64: value = reader.ReadInt64(); continue;
+                    case ProtoTypeCode.UInt16: value = reader.ReadUInt16(); continue;
+                    case ProtoTypeCode.UInt32: value = reader.ReadUInt32(); continue;
+                    case ProtoTypeCode.UInt64: value = reader.ReadUInt64(); continue;
+                    case ProtoTypeCode.Boolean: value = reader.ReadBoolean(); continue;
+                    case ProtoTypeCode.SByte: value = reader.ReadSByte(); continue;
+                    case ProtoTypeCode.Byte: value = reader.ReadByte(); continue;
+                    case ProtoTypeCode.Char: value = (char)reader.ReadUInt16(); continue;
+                    case ProtoTypeCode.Double: value = reader.ReadDouble(); continue;
+                    case ProtoTypeCode.Single: value = reader.ReadSingle(); continue;
+                    case ProtoTypeCode.DateTime: value = BclHelpers.ReadDateTime(reader); continue;
+                    case ProtoTypeCode.Decimal: value = BclHelpers.ReadDecimal(reader); continue;
+                    case ProtoTypeCode.String: value = reader.ReadString(); continue;
+                    case ProtoTypeCode.ByteArray: value = ProtoReader.AppendBytes((byte[])value, reader); continue;
+                    case ProtoTypeCode.TimeSpan: value = BclHelpers.ReadTimeSpan(reader); continue;
+                    case ProtoTypeCode.Guid: value = BclHelpers.ReadGuid(reader); continue;
+                    case ProtoTypeCode.Uri: value = new Uri(reader.ReadString()); continue; 
+                }
+
+            }
+            if (!found && !asListItem && autoCreate)
+            {
+                if (type != typeof(string))
+                {
+                    value = Activator.CreateInstance(type);
+                }
+            }
+            return found;
+        }
+#endif
+
+#if !NO_RUNTIME
+        /// <summary>
+        /// Creates a new runtime model, to which the caller
+        /// can add support for a range of types. A model
+        /// can be used "as is", or can be compiled for
+        /// optimal performance.
+        /// </summary>
+        public static RuntimeTypeModel Create()
+        {
+            return new RuntimeTypeModel(false);
+        }
+#endif
+
+        /// <summary>
+        /// Applies common proxy scenarios, resolving the actual type to consider
+        /// </summary>
+        protected internal static Type ResolveProxies(Type type)
+        {
+            if (type == null) return null;
+#if !NO_GENERICS            
+            if (type.IsGenericParameter) return null;
+            // Nullable<T>
+            Type tmp =  Helpers.GetUnderlyingType(type);
+            if (tmp != null) return tmp;
+#endif
+
+#if !(WINRT || CF)
+            // EF POCO
+            string fullName = type.FullName;
+            if (fullName != null && fullName.StartsWith("System.Data.Entity.DynamicProxies.")) return type.BaseType;
+
+            // NHibernate
+            Type[] interfaces = type.GetInterfaces();
+            for(int i = 0 ; i < interfaces.Length ; i++)
+            {
+                switch(interfaces[i].FullName)
+                {
+                    case "NHibernate.Proxy.INHibernateProxy":
+                    case "NHibernate.Proxy.DynamicProxy.IProxy":
+                    case "NHibernate.Intercept.IFieldInterceptorAccessor":
+                        return type.BaseType;
+                }
+            }
+#endif
+            return null;
+        }
+        /// <summary>
+        /// Indicates whether the supplied type is explicitly modelled by the model
+        /// </summary>
+        public bool IsDefined(Type type)
+        {
+            return GetKey(ref type) >= 0;
+        }
+        /// <summary>
+        /// Provides the key that represents a given type in the current model.
+        /// The type is also normalized for proxies at the same time.
+        /// </summary>
+        protected internal int GetKey(ref Type type)
+        {
+            if (type == null) return -1;
+            int key = GetKeyImpl(type);
+            if (key < 0)
+            {
+                Type normalized = ResolveProxies(type);
+                if (normalized != null) {
+                    type = normalized; // hence ref
+                    key = GetKeyImpl(type);
+                }
+            }
+            return key;
+        }
+
+        /// <summary>
+        /// Provides the key that represents a given type in the current model.
+        /// </summary>
+        protected abstract int GetKeyImpl(Type type);
+        /// <summary>
+        /// Writes a protocol-buffer representation of the given instance to the supplied stream.
+        /// </summary>
+        /// <param name="key">Represents the type (including inheritance) to consider.</param>
+        /// <param name="value">The existing instance to be serialized (cannot be null).</param>
+        /// <param name="dest">The destination stream to write to.</param>
+        protected internal abstract void Serialize(int key, object value, ProtoWriter dest);
+        /// <summary>
+        /// Applies a protocol-buffer stream to an existing instance (which may be null).
+        /// </summary>
+        /// <param name="key">Represents the type (including inheritance) to consider.</param>
+        /// <param name="value">The existing instance to be modified (can be null).</param>
+        /// <param name="source">The binary stream to apply to the instance (cannot be null).</param>
+        /// <returns>The updated instance; this may be different to the instance argument if
+        /// either the original instance was null, or the stream defines a known sub-type of the
+        /// original instance.</returns>
+        protected internal abstract object Deserialize(int key, object value, ProtoReader source);
+        
+        //internal ProtoSerializer Create(IProtoSerializer head)
+        //{
+        //    return new RuntimeSerializer(head, this);
+        //}
+        //internal ProtoSerializer Compile
+
+        /// <summary>
+        /// Indicates the type of callback to be used
+        /// </summary>
+        protected internal enum CallbackType
+        {
+            /// <summary>
+            /// Invoked before an object is serialized
+            /// </summary>
+            BeforeSerialize,
+            /// <summary>
+            /// Invoked after an object is serialized
+            /// </summary>
+            AfterSerialize,
+            /// <summary>
+            /// Invoked before an object is deserialized (or when a new instance is created)
+            /// </summary>            
+            BeforeDeserialize,
+            /// <summary>
+            /// Invoked after an object is deserialized
+            /// </summary>
+            AfterDeserialize
+        }
+        /// <summary>
+        /// Create a deep clone of the supplied instance; any sub-items are also cloned.
+        /// </summary>
+        public object DeepClone(object value)
+        {
+#if FEAT_IKVM
+            throw new NotSupportedException();
+#else
+            if (value == null) return null;
+            Type type = value.GetType();
+            int key = GetKey(ref type);
+
+            if (key >= 0 && !Helpers.IsEnum(type))
+            {
+                using (MemoryStream ms = new MemoryStream())
+                {
+                    using(ProtoWriter writer = new ProtoWriter(ms, this, null))
+                    {
+                        writer.SetRootObject(value);
+                        Serialize(key, value, writer);
+                        writer.Close();
+                    }
+                    ms.Position = 0;
+                    ProtoReader reader = null;
+                    try
+                    {
+                        reader = ProtoReader.Create(ms, this, null, ProtoReader.TO_EOF);
+                        return Deserialize(key, null, reader);
+                    }
+                    finally
+                    {
+                        ProtoReader.Recycle(reader);
+                    }
+                }
+            }
+            int modelKey;
+            if (type == typeof(byte[])) {
+                byte[] orig = (byte[])value, clone = new byte[orig.Length];
+                Helpers.BlockCopy(orig, 0, clone, 0, orig.Length);
+                return clone;
+            }
+            else if (GetWireType(Helpers.GetTypeCode(type), DataFormat.Default, ref type, out modelKey) != WireType.None && modelKey < 0)
+            {   // immutable; just return the original value
+                return value;
+            }
+            using (MemoryStream ms = new MemoryStream())
+            {
+                using (ProtoWriter writer = new ProtoWriter(ms, this, null))
+                {
+                    if (!TrySerializeAuxiliaryType(writer, type, DataFormat.Default, Serializer.ListItemTag, value, false)) ThrowUnexpectedType(type);
+                    writer.Close();
+                }
+                ms.Position = 0;
+                ProtoReader reader = null;
+                try
+                {
+                    reader = ProtoReader.Create(ms, this, null, ProtoReader.TO_EOF);
+                    value = null; // start from scratch!
+                    TryDeserializeAuxiliaryType(reader, DataFormat.Default, Serializer.ListItemTag, type, ref value, true, false, true, false);
+                    return value;
+                }
+                finally
+                {
+                    ProtoReader.Recycle(reader);
+                }
+            }
+#endif       
+
+        }
+
+        /// <summary>
+        /// Indicates that while an inheritance tree exists, the exact type encountered was not
+        /// specified in that hierarchy and cannot be processed.
+        /// </summary>
+        protected internal static void ThrowUnexpectedSubtype(Type expected, Type actual)
+        {
+            if (expected != TypeModel.ResolveProxies(actual))
+            {
+                throw new InvalidOperationException("Unexpected sub-type: " + actual.FullName);
+            }
+        }
+
+        /// <summary>
+        /// Indicates that the given type was not expected, and cannot be processed.
+        /// </summary>
+        protected internal static void ThrowUnexpectedType(Type type)
+        {
+            string fullName = type == null ? "(unknown)" : type.FullName;
+#if !NO_GENERICS && !WINRT
+            if (type != null)
+            {
+                Type baseType = type.BaseType;
+                if (baseType != null && baseType.IsGenericType && baseType.GetGenericTypeDefinition().Name == "GeneratedMessage`2")
+                {
+                    throw new InvalidOperationException(
+                        "Are you mixing protobuf-net and protobuf-csharp-port? See http://stackoverflow.com/q/11564914; type: " + fullName);
+                }
+            }
+#endif
+            throw new InvalidOperationException("Type is not expected, and no contract can be inferred: " + fullName);
+        }
+        internal static Exception CreateNestedListsNotSupported()
+        {
+            return new NotSupportedException("Nested or jagged lists and arrays are not supported");
+        }
+        /// <summary>
+        /// Indicates that the given type cannot be constructed; it may still be possible to 
+        /// deserialize into existing instances.
+        /// </summary>
+        public static void ThrowCannotCreateInstance(Type type)
+        {
+            throw new ProtoException("No parameterless constructor found for " + (type == null ? "(null)" : type.Name));
+        }
+
+        internal static string SerializeType(TypeModel model, System.Type type)
+        {
+            if (model != null)
+            {
+                TypeFormatEventHandler handler = model.DynamicTypeFormatting;
+                if (handler != null)
+                {
+                    TypeFormatEventArgs args = new TypeFormatEventArgs(type);
+                    handler(model, args);
+                    if (!Helpers.IsNullOrEmpty(args.FormattedName)) return args.FormattedName;
+                }
+            }
+            return type.AssemblyQualifiedName;
+        }
+
+        internal static System.Type DeserializeType(TypeModel model, string value)
+        {
+            
+            if (model != null)
+            {
+                TypeFormatEventHandler handler = model.DynamicTypeFormatting;
+                if (handler != null)
+                {
+                    TypeFormatEventArgs args = new TypeFormatEventArgs(value);
+                    handler(model, args);
+                    if (args.Type != null) return args.Type;
+                }
+            }
+            return System.Type.GetType(value);
+        }
+
+        /// <summary>
+        /// Returns true if the type supplied is either a recognised contract type,
+        /// or a *list* of a recognised contract type. 
+        /// </summary>
+        /// <remarks>Note that primitives always return false, even though the engine
+        /// will, if forced, try to serialize such</remarks>
+        /// <returns>True if this type is recognised as a serializable entity, else false</returns>
+        public bool CanSerializeContractType(Type type)
+        {
+            return CanSerialize(type, false, true, true);
+        }
+
+        /// <summary>
+        /// Returns true if the type supplied is a basic type with inbuilt handling,
+        /// a recognised contract type, or a *list* of a basic / contract type. 
+        /// </summary>
+        public bool CanSerialize(Type type)
+        {
+            return CanSerialize(type, true, true, true);
+        }
+
+        /// <summary>
+        /// Returns true if the type supplied is a basic type with inbuilt handling,
+        /// or a *list* of a basic type with inbuilt handling
+        /// </summary>
+        public bool CanSerializeBasicType(Type type)
+        {
+            return CanSerialize(type, true, false, true);
+        }
+        private bool CanSerialize(Type type, bool allowBasic, bool allowContract, bool allowLists)
+        {
+            if (type == null) throw new ArgumentNullException("type");
+            Type tmp = Helpers.GetUnderlyingType(type);
+            if (tmp != null) type = tmp;
+
+            // is it a basic type?
+            ProtoTypeCode typeCode = Helpers.GetTypeCode(type);
+            switch(typeCode)
+            {
+                case ProtoTypeCode.Empty:
+                case ProtoTypeCode.Unknown:
+                    break;
+                default:
+                    return allowBasic; // well-known basic type
+            }
+            int modelKey = GetKey(ref type);
+            if (modelKey >= 0) return allowContract; // known contract type
+
+            // is it a list?
+            if (allowLists)
+            {
+                Type itemType = null;
+                if (type.IsArray)
+                {   // note we don't need to exclude byte[], as that is handled by GetTypeCode already
+                    if (type.GetArrayRank() == 1) itemType = type.GetElementType();
+                }
+                else
+                {
+                    itemType = GetListItemType(this, type);
+                }
+                if (itemType != null) return CanSerialize(itemType, allowBasic, allowContract, false);
+            }
+            return false;
+        }
+
+        /// <summary>
+        /// Suggest a .proto definition for the given type
+        /// </summary>
+        /// <param name="type">The type to generate a .proto definition for, or <c>null</c> to generate a .proto that represents the entire model</param>
+        /// <returns>The .proto definition as a string</returns>
+        public virtual string GetSchema(Type type)
+        {
+            throw new NotSupportedException();
+        }
+
+        /// <summary>
+        /// Used to provide custom services for writing and parsing type names when using dynamic types. Both parsing and formatting
+        /// are provided on a single API as it is essential that both are mapped identically at all times.
+        /// </summary>
+        public event TypeFormatEventHandler DynamicTypeFormatting;
+
+#if PLAT_BINARYFORMATTER && !(WINRT || PHONE8)
+        /// <summary>
+        /// Creates a new IFormatter that uses protocol-buffer [de]serialization.
+        /// </summary>
+        /// <returns>A new IFormatter to be used during [de]serialization.</returns>
+        /// <param name="type">The type of object to be [de]deserialized by the formatter.</param>
+        public System.Runtime.Serialization.IFormatter CreateFormatter(Type type)
+        {
+            return new Formatter(this, type);
+        }
+
+        internal sealed class Formatter : System.Runtime.Serialization.IFormatter
+        {
+            private readonly TypeModel model;
+            private readonly Type type;
+            internal Formatter(TypeModel model, Type type)
+            {
+                if (model == null) throw new ArgumentNullException("model");
+                if (type == null) throw new ArgumentNullException("type");
+                this.model = model;
+                this.type = type;
+            }
+            private System.Runtime.Serialization.SerializationBinder binder;
+            public System.Runtime.Serialization.SerializationBinder Binder
+            {
+                get { return binder; }
+                set { binder = value; }
+            }
+
+            private System.Runtime.Serialization.StreamingContext context;
+            public System.Runtime.Serialization.StreamingContext Context
+            {
+                get { return context; }
+                set { context = value; }
+            }
+
+            public object Deserialize(Stream source)
+            {
+#if FEAT_IKVM
+                throw new NotSupportedException();
+#else
+                return model.Deserialize(source, null, type, -1, Context);
+#endif
+            }
+
+            public void Serialize(Stream destination, object graph)
+            {
+                model.Serialize(destination, graph, Context);
+            }
+
+            private System.Runtime.Serialization.ISurrogateSelector surrogateSelector;
+            public System.Runtime.Serialization.ISurrogateSelector SurrogateSelector
+            {
+                get { return surrogateSelector; }
+                set { surrogateSelector = value; }
+            }
+        }
+#endif
+
+#if DEBUG // this is used by some unit tests only, to ensure no buffering when buffering is disabled
+        private bool forwardsOnly;
+        /// <summary>
+        /// If true, buffering of nested objects is disabled
+        /// </summary>
+        public bool ForwardsOnly
+        {
+            get { return forwardsOnly; }
+            set { forwardsOnly = value; }
+        }
+#endif
+
+        internal virtual Type GetType(string fullName, Assembly context)
+        {
+#if FEAT_IKVM
+            throw new NotImplementedException();
+#else
+            return ResolveKnownType(fullName, this, context);
+#endif
+        }
+
+        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
+        internal static Type ResolveKnownType(string name, TypeModel model, Assembly assembly)
+        {
+            if (Helpers.IsNullOrEmpty(name)) return null;
+            try
+            {
+#if FEAT_IKVM
+                // looks like a NullReferenceException, but this should call into RuntimeTypeModel's version
+                Type type = model == null ? null : model.GetType(name, assembly);
+#else
+                Type type = Type.GetType(name);
+#endif
+                if (type != null) return type;
+            }
+            catch { }
+            try
+            {
+                int i = name.IndexOf(',');
+                string fullName = (i > 0 ? name.Substring(0, i) : name).Trim();
+#if !(WINRT || FEAT_IKVM)
+                if (assembly == null) assembly = Assembly.GetCallingAssembly();
+#endif
+                Type type = assembly == null ? null : assembly.GetType(fullName);
+                if (type != null) return type;
+            }
+            catch { }
+            return null;
+        }
+
+    }
+
+}
+

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/Meta/TypeModel.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: d78c4d24137b63147a6a76481b42aee8
+timeCreated: 1515899114
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 635 - 0
Unity/Assets/Plugins/protobuf-net/Meta/ValueMember.cs

@@ -0,0 +1,635 @@
+#if !NO_RUNTIME
+using System;
+
+using ProtoBuf.Serializers;
+using System.Globalization;
+
+#if FEAT_IKVM
+using Type = IKVM.Reflection.Type;
+using IKVM.Reflection;
+#else
+using System.Reflection;
+#endif
+
+namespace ProtoBuf.Meta
+{
+    /// <summary>
+    /// Represents a member (property/field) that is mapped to a protobuf field
+    /// </summary>
+    public class ValueMember
+    {
+        private readonly int fieldNumber;
+        /// <summary>
+        /// The number that identifies this member in a protobuf stream
+        /// </summary>
+        public int FieldNumber { get { return fieldNumber; } }
+        private readonly MemberInfo member;
+        /// <summary>
+        /// Gets the member (field/property) which this member relates to.
+        /// </summary>
+        public MemberInfo Member { get { return member; } }
+        private readonly Type parentType, itemType, defaultType, memberType;
+        private object defaultValue;
+        /// <summary>
+        /// Within a list / array / etc, the type of object for each item in the list (especially useful with ArrayList)
+        /// </summary>
+        public Type ItemType { get { return itemType; } }
+        /// <summary>
+        /// The underlying type of the member
+        /// </summary>
+        public Type MemberType { get { return memberType; } }
+        /// <summary>
+        /// For abstract types (IList etc), the type of concrete object to create (if required)
+        /// </summary>
+        public Type DefaultType { get { return defaultType; } }
+        /// <summary>
+        /// The type the defines the member
+        /// </summary>
+        public Type ParentType { get { return parentType; } }
+
+        /// <summary>
+        /// The default value of the item (members with this value will not be serialized)
+        /// </summary>
+        public object DefaultValue
+        {
+            get { return defaultValue; }
+            set {
+                ThrowIfFrozen();
+                defaultValue = value;
+            }
+        }
+
+        private readonly RuntimeTypeModel model;
+        /// <summary>
+        /// Creates a new ValueMember instance
+        /// </summary>
+        public ValueMember(RuntimeTypeModel model, Type parentType, int fieldNumber, MemberInfo member, Type memberType, Type itemType, Type defaultType, DataFormat dataFormat, object defaultValue) 
+            : this(model, fieldNumber,memberType, itemType, defaultType, dataFormat)
+        {
+            if (member == null) throw new ArgumentNullException("member");
+            if (parentType == null) throw new ArgumentNullException("parentType");
+            if (fieldNumber < 1 && !Helpers.IsEnum(parentType)) throw new ArgumentOutOfRangeException("fieldNumber");
+
+            this.member = member;
+            this.parentType = parentType;
+            if (fieldNumber < 1 && !Helpers.IsEnum(parentType)) throw new ArgumentOutOfRangeException("fieldNumber");
+//#if WINRT
+            if (defaultValue != null && model.MapType(defaultValue.GetType()) != memberType)
+//#else
+//            if (defaultValue != null && !memberType.IsInstanceOfType(defaultValue))
+//#endif
+            {
+                defaultValue = ParseDefaultValue(memberType, defaultValue);
+            }
+            this.defaultValue = defaultValue;
+
+            MetaType type = model.FindWithoutAdd(memberType);
+            if (type != null)
+            {
+                this.asReference = type.AsReferenceDefault;
+            }
+            else
+            { // we need to scan the hard way; can't risk recursion by fully walking it
+                this.asReference = MetaType.GetAsReferenceDefault(model, memberType);
+            }
+        }
+        /// <summary>
+        /// Creates a new ValueMember instance
+        /// </summary>
+        internal ValueMember(RuntimeTypeModel model, int fieldNumber, Type memberType, Type itemType, Type defaultType, DataFormat dataFormat) 
+        {
+
+            if (memberType == null) throw new ArgumentNullException("memberType");
+            if (model == null) throw new ArgumentNullException("model");
+            this.fieldNumber = fieldNumber;
+            this.memberType = memberType;
+            this.itemType = itemType;
+            this.defaultType = defaultType;
+
+            this.model = model;
+            this.dataFormat = dataFormat;
+        }
+        internal object GetRawEnumValue()
+        {
+#if WINRT || PORTABLE || CF || FX11
+            object value = ((FieldInfo)member).GetValue(null);
+            switch(Helpers.GetTypeCode(Enum.GetUnderlyingType(((FieldInfo)member).FieldType)))
+            {
+                case ProtoTypeCode.SByte: return (sbyte)value;
+                case ProtoTypeCode.Byte: return (byte)value;
+                case ProtoTypeCode.Int16: return (short)value;
+                case ProtoTypeCode.UInt16: return (ushort)value;
+                case ProtoTypeCode.Int32: return (int)value;
+                case ProtoTypeCode.UInt32: return (uint)value;
+                case ProtoTypeCode.Int64: return (long)value;
+                case ProtoTypeCode.UInt64: return (ulong)value;
+                default:
+                    throw new InvalidOperationException();
+            }
+#else
+            return ((FieldInfo)member).GetRawConstantValue();
+#endif
+        }
+        private static object ParseDefaultValue(Type type, object value)
+        {
+            {
+                Type tmp = Helpers.GetUnderlyingType(type);
+                if (tmp != null) type = tmp;
+            }
+            if (value is string)
+            {
+                string s = (string)value;
+                if (Helpers.IsEnum(type)) return Helpers.ParseEnum(type, s);
+
+                switch (Helpers.GetTypeCode(type))
+                {
+                    case ProtoTypeCode.Boolean: return bool.Parse(s);
+                    case ProtoTypeCode.Byte: return byte.Parse(s, NumberStyles.Integer, CultureInfo.InvariantCulture);
+                    case ProtoTypeCode.Char: // char.Parse missing on CF/phone7
+                        if (s.Length == 1) return s[0];
+                        throw new FormatException("Single character expected: \"" + s + "\"");
+                    case ProtoTypeCode.DateTime: return DateTime.Parse(s, CultureInfo.InvariantCulture);
+                    case ProtoTypeCode.Decimal: return decimal.Parse(s, NumberStyles.Any, CultureInfo.InvariantCulture);
+                    case ProtoTypeCode.Double: return double.Parse(s, NumberStyles.Any, CultureInfo.InvariantCulture);
+                    case ProtoTypeCode.Int16: return short.Parse(s, NumberStyles.Any, CultureInfo.InvariantCulture);
+                    case ProtoTypeCode.Int32: return int.Parse(s, NumberStyles.Any, CultureInfo.InvariantCulture);
+                    case ProtoTypeCode.Int64: return long.Parse(s, NumberStyles.Any, CultureInfo.InvariantCulture);
+                    case ProtoTypeCode.SByte: return sbyte.Parse(s, NumberStyles.Integer, CultureInfo.InvariantCulture);
+                    case ProtoTypeCode.Single: return float.Parse(s, NumberStyles.Any, CultureInfo.InvariantCulture);
+                    case ProtoTypeCode.String: return s;
+                    case ProtoTypeCode.UInt16: return ushort.Parse(s, NumberStyles.Any, CultureInfo.InvariantCulture);
+                    case ProtoTypeCode.UInt32: return uint.Parse(s, NumberStyles.Any, CultureInfo.InvariantCulture);
+                    case ProtoTypeCode.UInt64: return ulong.Parse(s, NumberStyles.Any, CultureInfo.InvariantCulture);
+                    case ProtoTypeCode.TimeSpan: return TimeSpan.Parse(s);
+                    case ProtoTypeCode.Uri: return s; // Uri is decorated as string
+                    case ProtoTypeCode.Guid: return new Guid(s);
+                }
+            }
+#if FEAT_IKVM
+            if (Helpers.IsEnum(type)) return value; // return the underlying type instead
+            System.Type convertType = null;
+            switch(Helpers.GetTypeCode(type))
+            {
+                case ProtoTypeCode.SByte: convertType = typeof(sbyte); break;
+                case ProtoTypeCode.Int16: convertType = typeof(short); break;
+                case ProtoTypeCode.Int32: convertType = typeof(int); break;
+                case ProtoTypeCode.Int64: convertType = typeof(long); break;
+                case ProtoTypeCode.Byte: convertType = typeof(byte); break;
+                case ProtoTypeCode.UInt16: convertType = typeof(ushort); break;
+                case ProtoTypeCode.UInt32: convertType = typeof(uint); break;
+                case ProtoTypeCode.UInt64: convertType = typeof(ulong); break;
+                case ProtoTypeCode.Single: convertType = typeof(float); break;
+                case ProtoTypeCode.Double: convertType = typeof(double); break;
+                case ProtoTypeCode.Decimal: convertType = typeof(decimal); break;
+            }
+            if(convertType != null) return Convert.ChangeType(value, convertType, CultureInfo.InvariantCulture);
+            throw new ArgumentException("Unable to process default value: " + value + ", " + type.FullName);
+#else
+            if (Helpers.IsEnum(type)) return Enum.ToObject(type, value);
+            return Convert.ChangeType(value, type, CultureInfo.InvariantCulture);
+#endif
+        }
+
+        private IProtoSerializer serializer;
+        internal IProtoSerializer Serializer
+        {
+            get
+            {
+                if (serializer == null) serializer = BuildSerializer();
+                return serializer;
+            }
+        }
+
+        private DataFormat dataFormat;
+        /// <summary>
+        /// Specifies the rules used to process the field; this is used to determine the most appropriate
+        /// wite-type, but also to describe subtypes <i>within</i> that wire-type (such as SignedVariant)
+        /// </summary>
+        public DataFormat DataFormat {
+            get { return dataFormat; }
+            set { ThrowIfFrozen(); this.dataFormat = value; }
+        }
+
+        /// <summary>
+        /// Indicates whether this field should follow strict encoding rules; this means (for example) that if a "fixed32"
+        /// is encountered when "variant" is defined, then it will fail (throw an exception) when parsing. Note that
+        /// when serializing the defined type is always used.
+        /// </summary>
+        public bool IsStrict
+        {
+            get { return HasFlag(OPTIONS_IsStrict); }
+            set { SetFlag(OPTIONS_IsStrict, value, true); }
+        }
+
+        /// <summary>
+        /// Indicates whether this field should use packed encoding (which can save lots of space for repeated primitive values).
+        /// This option only applies to list/array data of primitive types (int, double, etc).
+        /// </summary>
+        public bool IsPacked
+        {
+            get { return HasFlag(OPTIONS_IsPacked); }
+            set { SetFlag(OPTIONS_IsPacked, value, true); }
+        }
+
+        /// <summary>
+        /// Indicates whether this field should *repace* existing values (the default is false, meaning *append*).
+        /// This option only applies to list/array data.
+        /// </summary>
+        public bool OverwriteList
+        {
+            get { return HasFlag(OPTIONS_OverwriteList); }
+            set { SetFlag(OPTIONS_OverwriteList, value, true); }
+        }
+
+        /// <summary>
+        /// Indicates whether this field is mandatory.
+        /// </summary>
+        public bool IsRequired
+        {
+            get { return HasFlag(OPTIONS_IsRequired); }
+            set { SetFlag(OPTIONS_IsRequired, value, true); }
+        }
+
+        private bool asReference;
+        /// <summary>
+        /// Enables full object-tracking/full-graph support.
+        /// </summary>
+        public bool AsReference
+        {
+            get { return asReference; }
+            set { ThrowIfFrozen(); asReference = value; }
+        }
+
+        private bool dynamicType;
+        /// <summary>
+        /// Embeds the type information into the stream, allowing usage with types not known in advance.
+        /// </summary>
+        public bool DynamicType
+        {
+            get { return dynamicType; }
+            set { ThrowIfFrozen(); dynamicType = value; }
+        }
+
+        private MethodInfo getSpecified, setSpecified;
+        /// <summary>
+        /// Specifies methods for working with optional data members.
+        /// </summary>
+        /// <param name="getSpecified">Provides a method (null for none) to query whether this member should
+        /// be serialized; it must be of the form "bool {Method}()". The member is only serialized if the
+        /// method returns true.</param>
+        /// <param name="setSpecified">Provides a method (null for none) to indicate that a member was
+        /// deserialized; it must be of the form "void {Method}(bool)", and will be called with "true"
+        /// when data is found.</param>
+        public void SetSpecified(MethodInfo getSpecified, MethodInfo setSpecified)
+        {
+            if (getSpecified != null)
+            {
+                if (getSpecified.ReturnType != model.MapType(typeof(bool))
+                    || getSpecified.IsStatic
+                    || getSpecified.GetParameters().Length != 0)
+                {
+                    throw new ArgumentException("Invalid pattern for checking member-specified", "getSpecified");
+                }
+            }
+            if (setSpecified != null)
+            {
+                ParameterInfo[] args;
+                if (setSpecified.ReturnType != model.MapType(typeof(void))
+                    || setSpecified.IsStatic
+                    || (args = setSpecified.GetParameters()).Length != 1
+                    || args[0].ParameterType != model.MapType(typeof(bool)))
+                {
+                    throw new ArgumentException("Invalid pattern for setting member-specified", "setSpecified");
+                }
+            }
+            ThrowIfFrozen();
+            this.getSpecified = getSpecified;
+            this.setSpecified = setSpecified;
+            
+        }
+        private void ThrowIfFrozen()
+        {
+            if (serializer != null) throw new InvalidOperationException("The type cannot be changed once a serializer has been generated");
+        }
+        private IProtoSerializer BuildSerializer()
+        {
+            int opaqueToken = 0;
+            try
+            {
+                model.TakeLock(ref opaqueToken);// check nobody is still adding this type
+                WireType wireType;
+                Type finalType = itemType == null ? memberType : itemType;
+                IProtoSerializer ser = TryGetCoreSerializer(model, dataFormat, finalType, out wireType, asReference, dynamicType, OverwriteList, true);
+                if (ser == null)
+                {
+                    throw new InvalidOperationException("No serializer defined for type: " + finalType.FullName);
+                }
+
+                // apply tags
+                if (itemType != null && SupportNull)
+                {
+                    if(IsPacked)
+                    {
+                        throw new NotSupportedException("Packed encodings cannot support null values");
+                    }
+                    ser = new TagDecorator(NullDecorator.Tag, wireType, IsStrict, ser);
+                    ser = new NullDecorator(model, ser);
+                    ser = new TagDecorator(fieldNumber, WireType.StartGroup, false, ser);
+                }
+                else
+                {
+                    ser = new TagDecorator(fieldNumber, wireType, IsStrict, ser);
+                }
+                // apply lists if appropriate
+                if (itemType != null)
+                {                    
+#if NO_GENERICS
+                    Type underlyingItemType = itemType;
+#else
+                    Type underlyingItemType = SupportNull ? itemType : Helpers.GetUnderlyingType(itemType) ?? itemType;
+#endif
+                    Helpers.DebugAssert(underlyingItemType == ser.ExpectedType, "Wrong type in the tail; expected {0}, received {1}", ser.ExpectedType, underlyingItemType);
+                    if (memberType.IsArray)
+                    {
+                        ser = new ArrayDecorator(model, ser, fieldNumber, IsPacked, wireType, memberType, OverwriteList, SupportNull);
+                    }
+                    else
+                    {
+                        ser = ListDecorator.Create(model, memberType, defaultType, ser, fieldNumber, IsPacked, wireType, member != null && PropertyDecorator.CanWrite(model, member), OverwriteList, SupportNull);
+                    }
+                }
+                else if (defaultValue != null && !IsRequired && getSpecified == null)
+                {   // note: "ShouldSerialize*" / "*Specified" / etc ^^^^ take precedence over defaultValue,
+                    // as does "IsRequired"
+                    ser = new DefaultValueDecorator(model, defaultValue, ser);
+                }
+                if (memberType == model.MapType(typeof(Uri)))
+                {
+                    ser = new UriDecorator(model, ser);
+                }
+                if (member != null)
+                {
+                    PropertyInfo prop = member as PropertyInfo;
+                    if (prop != null)
+                    {
+                        ser = new PropertyDecorator(model, parentType, (PropertyInfo)member, ser);
+                    }
+                    else
+                    {
+                        FieldInfo fld = member as FieldInfo;
+                        if (fld != null)
+                        {
+                            ser = new FieldDecorator(parentType, (FieldInfo)member, ser);
+                        }
+                        else
+                        {
+                            throw new InvalidOperationException();
+                        }
+                    }
+                    if (getSpecified != null || setSpecified != null)
+                    {
+                        ser = new MemberSpecifiedDecorator(getSpecified, setSpecified, ser);
+                    }
+                }
+                return ser;
+            }
+            finally
+            {
+                model.ReleaseLock(opaqueToken);
+            }
+        }
+
+        private static WireType GetIntWireType(DataFormat format, int width) {
+            switch(format) {
+                case DataFormat.ZigZag: return WireType.SignedVariant;
+                case DataFormat.FixedSize: return width == 32 ? WireType.Fixed32 : WireType.Fixed64;
+                case DataFormat.TwosComplement:
+                case DataFormat.Default: return WireType.Variant;
+                default: throw new InvalidOperationException();
+            }
+        }
+        private static WireType GetDateTimeWireType(DataFormat format)
+        {
+            switch (format)
+            {
+                case DataFormat.Group: return WireType.StartGroup;
+                case DataFormat.FixedSize: return WireType.Fixed64;
+                case DataFormat.Default: return WireType.String;
+                default: throw new InvalidOperationException();
+            }
+        }
+
+        internal static IProtoSerializer TryGetCoreSerializer(RuntimeTypeModel model, DataFormat dataFormat, Type type, out WireType defaultWireType,
+            bool asReference, bool dynamicType, bool overwriteList, bool allowComplexTypes)
+        {
+#if !NO_GENERICS
+            {
+                Type tmp = Helpers.GetUnderlyingType(type);
+                if (tmp != null) type = tmp;
+            }
+#endif
+            if (Helpers.IsEnum(type))
+            {
+                if (allowComplexTypes && model != null)
+                {
+                    // need to do this before checking the typecode; an int enum will report Int32 etc
+                    defaultWireType = WireType.Variant;
+                    return new EnumSerializer(type, model.GetEnumMap(type));
+                }
+                else
+                { // enum is fine for adding as a meta-type
+                    defaultWireType = WireType.None;
+                    return null;
+                }
+            }
+            ProtoTypeCode code = Helpers.GetTypeCode(type);
+            switch (code)
+            {
+                case ProtoTypeCode.Int32:
+                    defaultWireType = GetIntWireType(dataFormat, 32);
+                    return new Int32Serializer(model);
+                case ProtoTypeCode.UInt32:
+                    defaultWireType = GetIntWireType(dataFormat, 32);
+                    return new UInt32Serializer(model);
+                case ProtoTypeCode.Int64:
+                    defaultWireType = GetIntWireType(dataFormat, 64);
+                    return new Int64Serializer(model);
+                case ProtoTypeCode.UInt64:
+                    defaultWireType = GetIntWireType(dataFormat, 64);
+                    return new UInt64Serializer(model);
+                case ProtoTypeCode.String:
+                    defaultWireType = WireType.String;
+                    if (asReference)
+                    {
+                        return new NetObjectSerializer(model, model.MapType(typeof(string)), 0, BclHelpers.NetObjectOptions.AsReference);
+                    }
+                    return new StringSerializer(model);
+                case ProtoTypeCode.Single:
+                    defaultWireType = WireType.Fixed32;
+                    return new SingleSerializer(model);
+                case ProtoTypeCode.Double:
+                    defaultWireType = WireType.Fixed64;
+                    return new DoubleSerializer(model);
+                case ProtoTypeCode.Boolean:
+                    defaultWireType = WireType.Variant;
+                    return new BooleanSerializer(model);
+                case ProtoTypeCode.DateTime:
+                    defaultWireType = GetDateTimeWireType(dataFormat);
+                    return new DateTimeSerializer(model);
+                case ProtoTypeCode.Decimal:
+                    defaultWireType = WireType.String;
+                    return new DecimalSerializer(model);
+                case ProtoTypeCode.Byte:
+                    defaultWireType = GetIntWireType(dataFormat, 32);
+                    return new ByteSerializer(model);
+                case ProtoTypeCode.SByte:
+                    defaultWireType = GetIntWireType(dataFormat, 32);
+                    return new SByteSerializer(model);
+                case ProtoTypeCode.Char:
+                    defaultWireType = WireType.Variant;
+                    return new CharSerializer(model);
+                case ProtoTypeCode.Int16:
+                    defaultWireType = GetIntWireType(dataFormat, 32);
+                    return new Int16Serializer(model);
+                case ProtoTypeCode.UInt16:
+                    defaultWireType = GetIntWireType(dataFormat, 32);
+                    return new UInt16Serializer(model);
+                case ProtoTypeCode.TimeSpan:
+                    defaultWireType = GetDateTimeWireType(dataFormat);
+                    return new TimeSpanSerializer(model);
+                case ProtoTypeCode.Guid:
+                    defaultWireType = WireType.String;
+                    return new GuidSerializer(model);
+                case ProtoTypeCode.Uri:
+                    defaultWireType = WireType.String;
+                    return new StringSerializer(model); // treat as string; wrapped in decorator later
+                case ProtoTypeCode.ByteArray:
+                    defaultWireType = WireType.String;
+                    return new BlobSerializer(model, overwriteList);
+                case ProtoTypeCode.Type:
+                    defaultWireType = WireType.String;
+                    return new SystemTypeSerializer(model);
+            }
+            IProtoSerializer parseable = model.AllowParseableTypes ? ParseableSerializer.TryCreate(type, model) : null;
+            if (parseable != null)
+            {
+                defaultWireType = WireType.String;
+                return parseable;
+            }
+            if (allowComplexTypes && model != null)
+            {
+                int key = model.GetKey(type, false, true);
+                if (asReference || dynamicType)
+                {
+                    defaultWireType = dataFormat == DataFormat.Group ? WireType.StartGroup : WireType.String;
+                    BclHelpers.NetObjectOptions options = BclHelpers.NetObjectOptions.None;
+                    if (asReference) options |= BclHelpers.NetObjectOptions.AsReference;
+                    if (dynamicType) options |= BclHelpers.NetObjectOptions.DynamicType;
+                    if (key >= 0)
+                    { // exists
+                        if (asReference && Helpers.IsValueType(type))
+                        {
+                            string message = "AsReference cannot be used with value-types";
+
+                            if (type.Name == "KeyValuePair`2")
+                            {
+                                message += "; please see http://stackoverflow.com/q/14436606/";
+                            }
+                            else
+                            {
+                                message += ": " + type.FullName;
+                            }
+                            throw new InvalidOperationException(message);
+                        }
+                        MetaType meta = model[type];
+                        if (asReference && meta.IsAutoTuple) options |= BclHelpers.NetObjectOptions.LateSet;                        
+                        if (meta.UseConstructor) options |= BclHelpers.NetObjectOptions.UseConstructor;
+                    }
+                    return new NetObjectSerializer(model, type, key, options);
+                }
+                if (key >= 0)
+                {
+                    defaultWireType = dataFormat == DataFormat.Group ? WireType.StartGroup : WireType.String;
+                    return new SubItemSerializer(type, key, model[type], true);
+                }
+            }
+            defaultWireType = WireType.None;
+            return null;
+        }
+
+
+        private string name;
+        internal void SetName(string name)
+        {
+            ThrowIfFrozen();
+            this.name = name;
+        }
+        /// <summary>
+        /// Gets the logical name for this member in the schema (this is not critical for binary serialization, but may be used
+        /// when inferring a schema).
+        /// </summary>
+        public string Name
+        {
+            get { return Helpers.IsNullOrEmpty(name) ? member.Name : name; }
+        }
+
+        private const byte
+           OPTIONS_IsStrict = 1,
+           OPTIONS_IsPacked = 2,
+           OPTIONS_IsRequired = 4,
+           OPTIONS_OverwriteList = 8,
+           OPTIONS_SupportNull = 16;
+
+        private byte flags;
+        private bool HasFlag(byte flag) { return (flags & flag) == flag; }
+        private void SetFlag(byte flag, bool value, bool throwIfFrozen)
+        {
+            if (throwIfFrozen && HasFlag(flag) != value)
+            {
+                ThrowIfFrozen();
+            }
+            if (value)
+                flags |= flag;
+            else
+                flags = (byte)(flags & ~flag);
+        }
+
+        /// <summary>
+        /// Should lists have extended support for null values? Note this makes the serialization less efficient.
+        /// </summary>
+        public bool SupportNull
+        {
+            get { return HasFlag(OPTIONS_SupportNull); }
+            set { SetFlag(OPTIONS_SupportNull, value, true);}
+        }
+
+        internal string GetSchemaTypeName(bool applyNetObjectProxy, ref bool requiresBclImport)
+        {
+            Type effectiveType = ItemType;
+            if (effectiveType == null) effectiveType = MemberType;
+            return model.GetSchemaTypeName(effectiveType, DataFormat, applyNetObjectProxy && asReference, applyNetObjectProxy && dynamicType, ref requiresBclImport);
+        }
+
+        
+        internal sealed class Comparer : System.Collections.IComparer
+#if !NO_GENERICS
+, System.Collections.Generic.IComparer<ValueMember>
+#endif
+        {
+            public static readonly Comparer Default = new Comparer();
+            public int Compare(object x, object y)
+            {
+                return Compare(x as ValueMember, y as ValueMember);
+            }
+            public int Compare(ValueMember x, ValueMember y)
+            {
+                if (ReferenceEquals(x, y)) return 0;
+                if (x == null) return -1;
+                if (y == null) return 1;
+
+                return x.FieldNumber.CompareTo(y.FieldNumber);
+            }
+        }
+    }
+}
+#endif

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/Meta/ValueMember.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 6d408a0bf9912c542980902a9c4dfe9b
+timeCreated: 1515899113
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 246 - 0
Unity/Assets/Plugins/protobuf-net/NetObjectCache.cs

@@ -0,0 +1,246 @@
+using System;
+using System.Collections;
+using ProtoBuf.Meta;
+
+namespace ProtoBuf
+{
+    internal sealed class NetObjectCache
+    {
+        internal const int Root = 0;
+        private MutableList underlyingList;
+
+        private MutableList List
+        {
+            get
+            {
+                if (underlyingList == null) underlyingList = new MutableList();
+                return underlyingList;
+            }
+        }
+
+
+        internal object GetKeyedObject(int key)
+        {
+            if (key-- == Root)
+            {
+                if (rootObject == null) throw new ProtoException("No root object assigned");
+                return rootObject;
+            }
+            BasicList list = List;
+
+            if (key < 0 || key >= list.Count)
+            {
+                Helpers.DebugWriteLine("Missing key: " + key);
+                throw new ProtoException("Internal error; a missing key occurred");
+            }
+
+            object tmp = list[key];
+            if (tmp == null)
+            {
+                throw new ProtoException("A deferred key does not have a value yet");
+            }
+            return tmp;
+        }
+
+        internal void SetKeyedObject(int key, object value)
+        {
+            if (key-- == Root)
+            {
+                if (value == null) throw new ArgumentNullException("value");
+                if (rootObject != null && ((object)rootObject != (object)value)) throw new ProtoException("The root object cannot be reassigned");
+                rootObject = value;
+            }
+            else
+            {
+                MutableList list = List;
+                if (key < list.Count)
+                {
+                    object oldVal = list[key];
+                    if (oldVal == null)
+                    {
+                        list[key] = value;
+                    }
+                    else if (!ReferenceEquals(oldVal, value) )
+                    {
+                        throw new ProtoException("Reference-tracked objects cannot change reference");
+                    } // otherwise was the same; nothing to do
+                }
+                else if (key != list.Add(value))
+                {
+                    throw new ProtoException("Internal error; a key mismatch occurred");
+                }
+            }
+        }
+
+        private object rootObject;
+        internal int AddObjectKey(object value, out bool existing)
+        {
+            if (value == null) throw new ArgumentNullException("value");
+
+            if ((object)value == (object)rootObject) // (object) here is no-op, but should be
+            {                                        // preserved even if this was typed - needs ref-check
+                existing = true;
+                return Root;
+            }
+
+            string s = value as string;
+            BasicList list = List;
+            int index;
+
+#if NO_GENERICS
+            
+            if(s == null)
+            {
+                if (objectKeys == null)
+                {
+                    objectKeys = new ReferenceHashtable();
+                    index = -1;
+                }
+                else
+                {
+                    object tmp = objectKeys[value];
+                    index = tmp == null ? -1 : (int) tmp;
+                }
+            }
+            else
+            {
+                if (stringKeys == null)
+                {
+                    stringKeys = new Hashtable();
+                    index = -1;
+                }
+                else
+                {
+                    object tmp = stringKeys[s];
+                    index = tmp == null ? -1 : (int) tmp;
+                }
+            }
+#else
+
+            if(s == null)
+            {
+#if CF || PORTABLE // CF has very limited proper object ref-tracking; so instead, we'll search it the hard way
+                index = list.IndexOfReference(value);
+#else
+                if (objectKeys == null) 
+                {
+                    objectKeys = new System.Collections.Generic.Dictionary<object, int>(ReferenceComparer.Default);
+                    index = -1;
+                }
+                else
+                {
+                    if (!objectKeys.TryGetValue(value, out index)) index = -1;
+                }
+#endif
+            }
+            else
+            {
+                if (stringKeys == null)
+                {
+                    stringKeys = new System.Collections.Generic.Dictionary<string, int>();
+                    index = -1;
+                } 
+                else
+                {
+                    if (!stringKeys.TryGetValue(s, out index)) index = -1;
+                }
+            }
+#endif
+
+            if (!(existing = index >= 0))
+            {
+                index = list.Add(value);
+
+                if (s == null)
+                {
+#if !CF && !PORTABLE // CF can't handle the object keys very well
+                    objectKeys.Add(value, index);
+#endif
+                }
+                else
+                {
+                    stringKeys.Add(s, index);
+                }
+            }
+            return index + 1;
+        }
+
+        private int trapStartIndex; // defaults to 0 - optimization for RegisterTrappedObject
+                                    // to make it faster at seeking to find deferred-objects
+
+        internal void RegisterTrappedObject(object value)
+        {
+            if (rootObject == null)
+            {
+                rootObject = value;
+            }
+            else
+            {
+                if(underlyingList != null)
+                {
+                    for (int i = trapStartIndex; i < underlyingList.Count; i++)
+                    {
+                        trapStartIndex = i + 1; // things never *become* null; whether or
+                                                // not the next item is null, it will never
+                                                // need to be checked again
+
+                        if(underlyingList[i] == null)
+                        {
+                            underlyingList[i] = value;    
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+#if NO_GENERICS
+        private ReferenceHashtable objectKeys;
+        private System.Collections.Hashtable stringKeys;
+        private class ReferenceHashtable : System.Collections.Hashtable
+        {
+            protected override int GetHash(object key)
+            {
+                return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(key);
+            }
+            protected override bool KeyEquals(object item, object key)
+            {
+                return item == key;
+            }
+        }   
+#else
+
+        private System.Collections.Generic.Dictionary<string, int> stringKeys;
+
+#if !CF && !PORTABLE // CF lacks the ability to get a robust reference-based hash-code, so we'll do it the harder way instead
+        private System.Collections.Generic.Dictionary<object, int> objectKeys;
+        private sealed class ReferenceComparer : System.Collections.Generic.IEqualityComparer<object>
+        {
+            public readonly static ReferenceComparer Default = new ReferenceComparer();
+            private ReferenceComparer() {}
+
+            bool System.Collections.Generic.IEqualityComparer<object>.Equals(object x, object y)
+            {
+                return x == y; // ref equality
+            }
+
+            int System.Collections.Generic.IEqualityComparer<object>.GetHashCode(object obj)
+            {
+                return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(obj);
+            }
+        }
+#endif
+
+#endif
+
+        internal void Clear()
+        {
+            trapStartIndex = 0;
+            rootObject = null;
+            if (underlyingList != null) underlyingList.Clear();
+            if (stringKeys != null) stringKeys.Clear();
+#if !CF && !PORTABLE
+            if (objectKeys != null) objectKeys.Clear();
+#endif
+        }
+    }
+}

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/NetObjectCache.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 71e939a48d063e846b0e2e78531059d1
+timeCreated: 1515899113
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 26 - 0
Unity/Assets/Plugins/protobuf-net/PrefixStyle.cs

@@ -0,0 +1,26 @@
+
+namespace ProtoBuf
+{
+    /// <summary>
+    /// Specifies the type of prefix that should be applied to messages.
+    /// </summary>
+    public enum PrefixStyle
+    {
+        /// <summary>
+        /// No length prefix is applied to the data; the data is terminated only be the end of the stream.
+        /// </summary>
+        None,
+        /// <summary>
+        /// A base-128 length prefix is applied to the data (efficient for short messages).
+        /// </summary>
+        Base128,
+        /// <summary>
+        /// A fixed-length (little-endian) length prefix is applied to the data (useful for compatibility).
+        /// </summary>
+        Fixed32,
+                /// <summary>
+        /// A fixed-length (big-endian) length prefix is applied to the data (useful for compatibility).
+        /// </summary>
+        Fixed32BigEndian
+    }
+}

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/PrefixStyle.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: ca4331de0cc111b45bd865cc72fb28ff
+timeCreated: 1515899114
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 0 - 9
Unity/Assets/Plugins/protobuf-net/Properties.meta

@@ -1,9 +0,0 @@
-fileFormatVersion: 2
-guid: 1177ef9b04432e7408703511a0b66120
-folderAsset: yes
-timeCreated: 1513686875
-licenseType: Free
-DefaultImporter:
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 

+ 165 - 0
Unity/Assets/Plugins/protobuf-net/ProtoContractAttribute.cs

@@ -0,0 +1,165 @@
+using System;
+
+namespace ProtoBuf
+{
+    /// <summary>
+    /// Indicates that a type is defined for protocol-buffer serialization.
+    /// </summary>
+    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Interface,
+        AllowMultiple = false, Inherited = false)]
+    public sealed class ProtoContractAttribute : Attribute
+    {
+        /// <summary>
+        /// Gets or sets the defined name of the type.
+        /// </summary>
+        public string Name { get { return name; } set { name = value; } }
+        private string name;
+
+        /// <summary>
+        /// Gets or sets the fist offset to use with implicit field tags;
+        /// only uesd if ImplicitFields is set.
+        /// </summary>
+        public int ImplicitFirstTag
+        {
+            get { return implicitFirstTag; }
+            set
+            {
+                if (value < 1) throw new ArgumentOutOfRangeException("ImplicitFirstTag");
+                implicitFirstTag = value;
+            }
+        }
+        private int implicitFirstTag;
+
+        /// <summary>
+        /// If specified, alternative contract markers (such as markers for XmlSerailizer or DataContractSerializer) are ignored.
+        /// </summary>
+        public bool UseProtoMembersOnly
+        {
+            get { return HasFlag(OPTIONS_UseProtoMembersOnly); }
+            set { SetFlag(OPTIONS_UseProtoMembersOnly, value); }
+        }
+
+        /// <summary>
+        /// If specified, do NOT treat this type as a list, even if it looks like one.
+        /// </summary>
+        public bool IgnoreListHandling
+        {
+            get { return HasFlag(OPTIONS_IgnoreListHandling); }
+            set { SetFlag(OPTIONS_IgnoreListHandling, value); }
+        }
+
+
+        /// <summary>
+        /// Gets or sets the mechanism used to automatically infer field tags
+        /// for members. This option should be used in advanced scenarios only.
+        /// Please review the important notes against the ImplicitFields enumeration.
+        /// </summary>
+        public ImplicitFields ImplicitFields { get { return implicitFields; } set { implicitFields = value; } }
+        private ImplicitFields implicitFields;
+
+
+        /// <summary>
+        /// Enables/disables automatic tag generation based on the existing name / order
+        /// of the defined members. This option is not used for members marked
+        /// with ProtoMemberAttribute, as intended to provide compatibility with
+        /// WCF serialization. WARNING: when adding new fields you must take
+        /// care to increase the Order for new elements, otherwise data corruption
+        /// may occur.
+        /// </summary>
+        /// <remarks>If not explicitly specified, the default is assumed from Serializer.GlobalOptions.InferTagFromName.</remarks>
+        public bool InferTagFromName
+        {
+            get { return HasFlag(OPTIONS_InferTagFromName); }
+            set {
+                SetFlag(OPTIONS_InferTagFromName, value);
+                SetFlag(OPTIONS_InferTagFromNameHasValue, true);
+            }
+        }
+
+        /// <summary>
+        /// Has a InferTagFromName value been explicitly set? if not, the default from the type-model is assumed.
+        /// </summary>
+        internal bool InferTagFromNameHasValue
+        { // note that this property is accessed via reflection and should not be removed
+            get { return HasFlag(OPTIONS_InferTagFromNameHasValue); }
+        }
+
+        private int dataMemberOffset;
+
+        /// <summary>
+        /// Specifies an offset to apply to [DataMember(Order=...)] markers;
+        /// this is useful when working with mex-generated classes that have
+        /// a different origin (usually 1 vs 0) than the original data-contract.
+        /// 
+        /// This value is added to the Order of each member.
+        /// </summary>
+        public int DataMemberOffset
+        {
+            get { return dataMemberOffset; }
+            set { dataMemberOffset = value; }
+        }
+
+
+        /// <summary>
+        /// If true, the constructor for the type is bypassed during deserialization, meaning any field initializers
+        /// or other initialization code is skipped.
+        /// </summary>
+        public bool SkipConstructor
+        {
+            get { return HasFlag(OPTIONS_SkipConstructor); }
+            set { SetFlag(OPTIONS_SkipConstructor, value); }
+        }
+
+        /// <summary>
+        /// Should this type be treated as a reference by default? Please also see the implications of this,
+        /// as recorded on ProtoMemberAttribute.AsReference
+        /// </summary>
+        public bool AsReferenceDefault
+        {
+            get { return HasFlag(OPTIONS_AsReferenceDefault); }
+            set {
+                SetFlag(OPTIONS_AsReferenceDefault, value);
+            }
+        }
+
+        private bool HasFlag(byte flag) { return (flags & flag) == flag; }
+        private void SetFlag(byte flag, bool value)
+        {
+            if (value) flags |= flag;
+            else flags = (byte)(flags & ~flag);
+        }
+
+        private byte flags;
+
+        private const byte
+            OPTIONS_InferTagFromName = 1,
+            OPTIONS_InferTagFromNameHasValue = 2,
+            OPTIONS_UseProtoMembersOnly = 4,
+            OPTIONS_SkipConstructor = 8,
+            OPTIONS_IgnoreListHandling = 16,
+            OPTIONS_AsReferenceDefault = 32,
+            OPTIONS_EnumPassthru = 64,
+            OPTIONS_EnumPassthruHasValue = 128;
+
+        /// <summary>
+        /// Applies only to enums (not to DTO classes themselves); gets or sets a value indicating that an enum should be treated directly as an int/short/etc, rather
+        /// than enforcing .proto enum rules. This is useful *in particul* for [Flags] enums.
+        /// </summary>
+        public bool EnumPassthru
+        {
+            get { return HasFlag(OPTIONS_EnumPassthru); }
+            set {
+                SetFlag(OPTIONS_EnumPassthru, value);
+                SetFlag(OPTIONS_EnumPassthruHasValue, true);
+            }
+        }
+
+        /// <summary>
+        /// Has a EnumPassthru value been explicitly set?
+        /// </summary>
+        internal bool EnumPassthruHasValue
+        { // note that this property is accessed via reflection and should not be removed
+            get { return HasFlag(OPTIONS_EnumPassthruHasValue); }
+        }
+    }
+}

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/ProtoContractAttribute.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 633c13e01b94f3547b29e7ea206404ef
+timeCreated: 1515899113
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 13 - 0
Unity/Assets/Plugins/protobuf-net/ProtoConverterAttribute.cs

@@ -0,0 +1,13 @@
+using System;
+
+namespace ProtoBuf
+{
+    /// <summary>
+    /// Indicates that a static member should be considered the same as though
+    /// were an implicit / explicit conversion operator; in particular, this
+    /// is useful for conversions that operator syntax does not allow, such as
+    /// to/from interface types.
+    /// </summary>
+    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
+    public class ProtoConverterAttribute : Attribute {}
+}

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/ProtoConverterAttribute.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 9b016ecf3f3483b4383b6c647ba4c258
+timeCreated: 1515899113
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 37 - 0
Unity/Assets/Plugins/protobuf-net/ProtoEnumAttribute.cs

@@ -0,0 +1,37 @@
+using System;
+
+namespace ProtoBuf
+{
+    /// <summary>
+    /// Used to define protocol-buffer specific behavior for
+    /// enumerated values.
+    /// </summary>
+    [AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
+    public sealed class ProtoEnumAttribute : Attribute
+    {
+        /// <summary>
+        /// Gets or sets the specific value to use for this enum during serialization.
+        /// </summary>
+        public int Value
+        {
+            get { return enumValue; }
+            set { this.enumValue = value; hasValue = true; }
+        }
+
+        /// <summary>
+        /// Indicates whether this instance has a customised value mapping
+        /// </summary>
+        /// <returns>true if a specific value is set</returns>
+        public bool HasValue() { return hasValue; }
+
+        private bool hasValue;
+        private int enumValue;
+
+        /// <summary>
+        /// Gets or sets the defined name of the enum, as used in .proto
+        /// (this name is not used during serialization).
+        /// </summary>
+        public string Name { get { return name; } set { name = value; } }
+        private string name;
+    }
+}

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/ProtoEnumAttribute.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 6931279ae75066e4080fb9e743458cf5
+timeCreated: 1515899113
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 30 - 0
Unity/Assets/Plugins/protobuf-net/ProtoException.cs

@@ -0,0 +1,30 @@
+using System;
+
+#if PLAT_BINARYFORMATTER && !(WINRT || PHONE8)
+using System.Runtime.Serialization;
+#endif
+namespace ProtoBuf
+{
+    /// <summary>
+    /// Indicates an error during serialization/deserialization of a proto stream.
+    /// </summary>
+#if PLAT_BINARYFORMATTER && !(WINRT || PHONE8)
+    [Serializable]
+#endif
+    public class ProtoException : Exception
+    {
+        /// <summary>Creates a new ProtoException instance.</summary>
+        public ProtoException() { }
+
+        /// <summary>Creates a new ProtoException instance.</summary>
+        public ProtoException(string message) : base(message) { }
+
+        /// <summary>Creates a new ProtoException instance.</summary>
+        public ProtoException(string message, Exception innerException) : base(message, innerException) { }
+
+#if PLAT_BINARYFORMATTER && !(WINRT || PHONE8)
+        /// <summary>Creates a new ProtoException instance.</summary>
+        protected ProtoException(SerializationInfo info, StreamingContext context) : base(info, context) { }
+#endif
+    }
+}

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/ProtoException.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 7ee8f571753cacc4fafaaab2de2f255d
+timeCreated: 1515899113
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 40 - 0
Unity/Assets/Plugins/protobuf-net/ProtoIgnoreAttribute.cs

@@ -0,0 +1,40 @@
+using System;
+
+namespace ProtoBuf
+{
+    /// <summary>
+    /// Indicates that a member should be excluded from serialization; this
+    /// is only normally used when using implict fields.
+    /// </summary>
+    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field,
+        AllowMultiple = false, Inherited = true)]
+    public class ProtoIgnoreAttribute : Attribute {}
+
+    /// <summary>
+    /// Indicates that a member should be excluded from serialization; this
+    /// is only normally used when using implict fields. This allows
+    /// ProtoIgnoreAttribute usage
+    /// even for partial classes where the individual members are not
+    /// under direct control.
+    /// </summary>
+    [AttributeUsage(AttributeTargets.Class,
+            AllowMultiple = true, Inherited = false)]
+    public sealed class ProtoPartialIgnoreAttribute : ProtoIgnoreAttribute
+    {
+        /// <summary>
+        /// Creates a new ProtoPartialIgnoreAttribute instance.
+        /// </summary>
+        /// <param name="memberName">Specifies the member to be ignored.</param>
+        public ProtoPartialIgnoreAttribute(string memberName)
+            : base()
+        {
+            if (Helpers.IsNullOrEmpty(memberName)) throw new ArgumentNullException("memberName");
+            this.memberName = memberName;
+        }
+        /// <summary>
+        /// The name of the member to be ignored.
+        /// </summary>
+        public string MemberName { get { return memberName; } }
+        private readonly string memberName;
+    }
+}

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/ProtoIgnoreAttribute.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: b1947367b1444b140a2ea1d6537ac3d2
+timeCreated: 1515899114
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 78 - 0
Unity/Assets/Plugins/protobuf-net/ProtoIncludeAttribute.cs

@@ -0,0 +1,78 @@
+using System;
+using System.ComponentModel;
+
+using ProtoBuf.Meta;
+#if FEAT_IKVM
+using Type = IKVM.Reflection.Type;
+using IKVM.Reflection;
+#else
+using System.Reflection;
+#endif
+namespace ProtoBuf
+{
+    /// <summary>
+    /// Indicates the known-types to support for an individual
+    /// message. This serializes each level in the hierarchy as
+    /// a nested message to retain wire-compatibility with
+    /// other protocol-buffer implementations.
+    /// </summary>
+    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = true, Inherited = false)]
+    public sealed class ProtoIncludeAttribute : Attribute
+    {
+        ///<summary>
+        /// Creates a new instance of the ProtoIncludeAttribute.
+        /// </summary>
+        /// <param name="tag">The unique index (within the type) that will identify this data.</param>
+        /// <param name="knownType">The additional type to serialize/deserialize.</param>
+        public ProtoIncludeAttribute(int tag, System.Type knownType)
+            : this(tag, knownType == null ? "" : knownType.AssemblyQualifiedName) { }
+
+        /// <summary>
+        /// Creates a new instance of the ProtoIncludeAttribute.
+        /// </summary>
+        /// <param name="tag">The unique index (within the type) that will identify this data.</param>
+        /// <param name="knownTypeName">The additional type to serialize/deserialize.</param>
+        public ProtoIncludeAttribute(int tag, string knownTypeName)
+        {
+            if (tag <= 0) throw new ArgumentOutOfRangeException("tag", "Tags must be positive integers");
+            if (Helpers.IsNullOrEmpty(knownTypeName)) throw new ArgumentNullException("knownTypeName", "Known type cannot be blank");
+            this.tag = tag;
+            this.knownTypeName = knownTypeName;
+        }
+
+        /// <summary>
+        /// Gets the unique index (within the type) that will identify this data.
+        /// </summary>
+        public int Tag { get { return tag; } }
+        private readonly int tag;
+
+        /// <summary>
+        /// Gets the additional type to serialize/deserialize.
+        /// </summary>
+        public string KnownTypeName { get { return knownTypeName; } }
+        private readonly string knownTypeName;
+
+        /// <summary>
+        /// Gets the additional type to serialize/deserialize.
+        /// </summary>
+        public Type KnownType
+        {
+            get
+            {
+                return TypeModel.ResolveKnownType(KnownTypeName, null, null);
+            }
+        }
+
+        /// <summary>
+        /// Specifies whether the inherited sype's sub-message should be
+        /// written with a length-prefix (default), or with group markers.
+        /// </summary>
+        [DefaultValue(DataFormat.Default)]
+        public DataFormat DataFormat
+        {
+            get { return dataFormat; }
+            set { dataFormat = value; }
+        }
+        private DataFormat dataFormat = DataFormat.Default;
+    }
+}

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/ProtoIncludeAttribute.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 2101ff19e579fd946a19bc3f81ecb8b2
+timeCreated: 1515899112
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 231 - 0
Unity/Assets/Plugins/protobuf-net/ProtoMemberAttribute.cs

@@ -0,0 +1,231 @@
+using System;
+
+#if FEAT_IKVM
+using Type = IKVM.Reflection.Type;
+using IKVM.Reflection;
+#else
+using System.Reflection;
+#endif
+
+namespace ProtoBuf
+{
+    /// <summary>
+    /// Declares a member to be used in protocol-buffer serialization, using
+    /// the given Tag. A DataFormat may be used to optimise the serialization
+    /// format (for instance, using zigzag encoding for negative numbers, or 
+    /// fixed-length encoding for large values.
+    /// </summary>
+    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field,
+        AllowMultiple = false, Inherited = true)]
+    public class ProtoMemberAttribute : Attribute
+        , IComparable
+#if !NO_GENERICS
+        , IComparable<ProtoMemberAttribute>
+#endif
+
+    {
+        /// <summary>
+        /// Compare with another ProtoMemberAttribute for sorting purposes
+        /// </summary>
+        public int CompareTo(object other) { return CompareTo(other as ProtoMemberAttribute); }
+        /// <summary>
+        /// Compare with another ProtoMemberAttribute for sorting purposes
+        /// </summary>
+        public int CompareTo(ProtoMemberAttribute other)
+        {
+            if (other == null) return -1;
+            if ((object)this == (object)other) return 0;
+            int result = this.tag.CompareTo(other.tag);
+            if (result == 0) result = string.CompareOrdinal(this.name, other.name);
+            return result;
+        }
+
+        /// <summary>
+        /// Creates a new ProtoMemberAttribute instance.
+        /// </summary>
+        /// <param name="tag">Specifies the unique tag used to identify this member within the type.</param>
+        public ProtoMemberAttribute(int tag) : this(tag, false)
+        { }
+
+        internal ProtoMemberAttribute(int tag, bool forced)
+        {
+            if (tag <= 0 && !forced) throw new ArgumentOutOfRangeException("tag");
+            this.tag = tag;
+        }
+
+#if !NO_RUNTIME
+        internal MemberInfo Member;
+        internal bool TagIsPinned;
+#endif
+        /// <summary>
+        /// Gets or sets the original name defined in the .proto; not used
+        /// during serialization.
+        /// </summary>
+        public string Name { get { return name; } set { name = value; } }
+        private string name;
+
+        /// <summary>
+        /// Gets or sets the data-format to be used when encoding this value.
+        /// </summary>
+        public DataFormat DataFormat { get { return dataFormat; } set { dataFormat = value; } }
+        private DataFormat dataFormat; 
+
+        /// <summary>
+        /// Gets the unique tag used to identify this member within the type.
+        /// </summary>
+        public int Tag { get { return tag; } }
+        private int tag;
+        internal void Rebase(int tag) { this.tag = tag; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether this member is mandatory.
+        /// </summary>
+        public bool IsRequired {
+            get { return (options & MemberSerializationOptions.Required) == MemberSerializationOptions.Required; }
+            set {
+                if (value) options |= MemberSerializationOptions.Required;
+                else options &= ~MemberSerializationOptions.Required;
+            }
+        }
+
+        /// <summary>
+        /// Gets a value indicating whether this member is packed.
+        /// This option only applies to list/array data of primitive types (int, double, etc).
+        /// </summary>
+        public bool IsPacked
+        {
+            get { return (options & MemberSerializationOptions.Packed) == MemberSerializationOptions.Packed;}
+            set {
+                if (value) options |= MemberSerializationOptions.Packed;
+                else options &= ~MemberSerializationOptions.Packed;
+            }
+        }
+
+        /// <summary>
+        /// Indicates whether this field should *repace* existing values (the default is false, meaning *append*).
+        /// This option only applies to list/array data.
+        /// </summary>
+        public bool OverwriteList
+        {
+            get { return (options & MemberSerializationOptions.OverwriteList) == MemberSerializationOptions.OverwriteList; }
+            set
+            {
+                if (value) options |= MemberSerializationOptions.OverwriteList;
+                else options &= ~MemberSerializationOptions.OverwriteList;
+            }
+        }
+
+        /// <summary>
+        /// Enables full object-tracking/full-graph support.
+        /// </summary>
+        public bool AsReference
+        {
+            get { return (options & MemberSerializationOptions.AsReference) == MemberSerializationOptions.AsReference; }
+            set
+            {
+                if (value) options |= MemberSerializationOptions.AsReference;
+                else options &= ~MemberSerializationOptions.AsReference;
+
+                options |= MemberSerializationOptions.AsReferenceHasValue;
+            }
+        }
+
+        internal bool AsReferenceHasValue
+        {
+            get { return (options & MemberSerializationOptions.AsReferenceHasValue) == MemberSerializationOptions.AsReferenceHasValue; }
+            set {
+                if (value) options |= MemberSerializationOptions.AsReferenceHasValue;
+                else options &= ~MemberSerializationOptions.AsReferenceHasValue;
+            }
+        }
+
+        /// <summary>
+        /// Embeds the type information into the stream, allowing usage with types not known in advance.
+        /// </summary>
+        public bool DynamicType
+        {
+            get { return (options & MemberSerializationOptions.DynamicType) == MemberSerializationOptions.DynamicType; }
+            set
+            {
+                if (value) options |= MemberSerializationOptions.DynamicType;
+                else options &= ~MemberSerializationOptions.DynamicType;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether this member is packed (lists/arrays).
+        /// </summary>
+        public MemberSerializationOptions Options { get { return options; } set { options = value; } }
+        private MemberSerializationOptions options;
+
+        
+    }
+
+    /// <summary>
+    /// Additional (optional) settings that control serialization of members
+    /// </summary>
+    [Flags]
+    public enum MemberSerializationOptions
+    {
+        /// <summary>
+        /// Default; no additional options
+        /// </summary>
+        None = 0,
+        /// <summary>
+        /// Indicates that repeated elements should use packed (length-prefixed) encoding
+        /// </summary>
+        Packed = 1,
+        /// <summary>
+        /// Indicates that the given item is required
+        /// </summary>
+        Required = 2,
+        /// <summary>
+        /// Enables full object-tracking/full-graph support
+        /// </summary>
+        AsReference = 4,
+        /// <summary>
+        /// Embeds the type information into the stream, allowing usage with types not known in advance
+        /// </summary>
+        DynamicType = 8,
+        /// <summary>
+        /// Indicates whether this field should *repace* existing values (the default is false, meaning *append*).
+        /// This option only applies to list/array data.
+        /// </summary>
+        OverwriteList = 16,
+        /// <summary>
+        /// Determines whether the types AsReferenceDefault value is used, or whether this member's AsReference should be used
+        /// </summary>
+        AsReferenceHasValue = 32
+    }
+
+    /// <summary>
+    /// Declares a member to be used in protocol-buffer serialization, using
+    /// the given Tag and MemberName. This allows ProtoMemberAttribute usage
+    /// even for partial classes where the individual members are not
+    /// under direct control.
+    /// A DataFormat may be used to optimise the serialization
+    /// format (for instance, using zigzag encoding for negative numbers, or 
+    /// fixed-length encoding for large values.
+    /// </summary>
+    [AttributeUsage(AttributeTargets.Class,
+            AllowMultiple = true, Inherited = false)]
+    public sealed class ProtoPartialMemberAttribute : ProtoMemberAttribute
+    {
+        /// <summary>
+        /// Creates a new ProtoMemberAttribute instance.
+        /// </summary>
+        /// <param name="tag">Specifies the unique tag used to identify this member within the type.</param>
+        /// <param name="memberName">Specifies the member to be serialized.</param>
+        public ProtoPartialMemberAttribute(int tag, string memberName)
+            : base(tag)
+        {
+            if (Helpers.IsNullOrEmpty(memberName)) throw new ArgumentNullException("memberName");
+            this.memberName = memberName;
+        }
+        /// <summary>
+        /// The name of the member to be serialized.
+        /// </summary>
+        public string MemberName { get { return memberName; } }
+        private readonly string memberName;
+    }
+}

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/ProtoMemberAttribute.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 7146d0c77c2068b439633292a9e7b185
+timeCreated: 1515899113
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 1414 - 0
Unity/Assets/Plugins/protobuf-net/ProtoReader.cs

@@ -0,0 +1,1414 @@
+
+using System;
+
+using System.IO;
+using System.Text;
+using ProtoBuf.Meta;
+
+#if FEAT_IKVM
+using Type = IKVM.Reflection.Type;
+#endif
+
+#if MF
+using EndOfStreamException = System.ApplicationException;
+using OverflowException = System.ApplicationException;
+#endif
+
+namespace ProtoBuf
+{
+    /// <summary>
+    /// A stateful reader, used to read a protobuf stream. Typical usage would be (sequentially) to call
+    /// ReadFieldHeader and (after matching the field) an appropriate Read* method.
+    /// </summary>
+    public sealed class ProtoReader : IDisposable
+    {
+        Stream source;
+        byte[] ioBuffer;
+        TypeModel model;
+        int fieldNumber, depth, dataRemaining, ioIndex, position, available, blockEnd;
+        WireType wireType;
+        bool isFixedLength, internStrings;
+        private NetObjectCache netCache;
+
+        // this is how many outstanding objects do not currently have
+        // values for the purposes of reference tracking; we'll default
+        // to just trapping the root object
+        // note: objects are trapped (the ref and key mapped) via NoteObject
+        uint trapCount; // uint is so we can use beq/bne more efficiently than bgt
+
+
+        /// <summary>
+        /// Gets the number of the field being processed.
+        /// </summary>
+        public int FieldNumber { get { return fieldNumber; } }
+        /// <summary>
+        /// Indicates the underlying proto serialization format on the wire.
+        /// </summary>
+        public WireType WireType { get { return wireType; } }
+
+        /// <summary>
+        /// Creates a new reader against a stream
+        /// </summary>
+        /// <param name="source">The source stream</param>
+        /// <param name="model">The model to use for serialization; this can be null, but this will impair the ability to deserialize sub-objects</param>
+        /// <param name="context">Additional context about this serialization operation</param>
+        public ProtoReader(Stream source, TypeModel model, SerializationContext context) 
+        {
+            Init(this, source, model, context, TO_EOF);
+        }
+
+        internal const int TO_EOF = -1;
+        
+        
+        /// <summary>
+        /// Gets / sets a flag indicating whether strings should be checked for repetition; if
+        /// true, any repeated UTF-8 byte sequence will result in the same String instance, rather
+        /// than a second instance of the same string. Enabled by default. Note that this uses
+        /// a <i>custom</i> interner - the system-wide string interner is not used.
+        /// </summary>
+        public bool InternStrings { get { return internStrings; } set { internStrings = value; } }
+
+        /// <summary>
+        /// Creates a new reader against a stream
+        /// </summary>
+        /// <param name="source">The source stream</param>
+        /// <param name="model">The model to use for serialization; this can be null, but this will impair the ability to deserialize sub-objects</param>
+        /// <param name="context">Additional context about this serialization operation</param>
+        /// <param name="length">The number of bytes to read, or -1 to read until the end of the stream</param>
+        public ProtoReader(Stream source, TypeModel model, SerializationContext context, int length)
+        {
+            Init(this, source, model, context, length);
+        }
+
+        private static void Init(ProtoReader reader, Stream source, TypeModel model, SerializationContext context, int length)
+        {
+            if (source == null) throw new ArgumentNullException("source");
+            if (!source.CanRead) throw new ArgumentException("Cannot read from stream", "source");
+            reader.source = source;
+            reader.ioBuffer = BufferPool.GetBuffer();
+            reader.model = model;
+            bool isFixedLength = length >= 0;
+            reader.isFixedLength = isFixedLength;
+            reader.dataRemaining = isFixedLength ? length : 0;
+
+            if (context == null) { context = SerializationContext.Default; }
+            else { context.Freeze(); }
+            reader.context = context;
+            reader.position = reader.available = reader.depth = reader.fieldNumber = reader.ioIndex = 0;
+            reader.blockEnd = int.MaxValue;
+            reader.internStrings = true;
+            reader.wireType = WireType.None;
+            reader.trapCount = 1;
+            if(reader.netCache == null) reader.netCache = new NetObjectCache();            
+        }
+
+        private SerializationContext context;
+
+        /// <summary>
+        /// Addition information about this deserialization operation.
+        /// </summary>
+        public SerializationContext Context { get { return context; } }
+        /// <summary>
+        /// Releases resources used by the reader, but importantly <b>does not</b> Dispose the 
+        /// underlying stream; in many typical use-cases the stream is used for different
+        /// processes, so it is assumed that the consumer will Dispose their stream separately.
+        /// </summary>
+        public void Dispose()
+        {
+            // importantly, this does **not** own the stream, and does not dispose it
+            source = null;
+            model = null;
+            BufferPool.ReleaseBufferToPool(ref ioBuffer);
+            if(stringInterner != null) stringInterner.Clear();
+            if(netCache != null) netCache.Clear();
+        }
+        internal int TryReadUInt32VariantWithoutMoving(bool trimNegative, out uint value)
+        {
+            if (available < 10) Ensure(10, false);
+            if (available == 0)
+            {
+                value = 0;
+                return 0;
+            }
+            int readPos = ioIndex;
+            value = ioBuffer[readPos++];
+            if ((value & 0x80) == 0) return 1;
+            value &= 0x7F;
+            if (available == 1) throw EoF(this);
+
+            uint chunk = ioBuffer[readPos++];
+            value |= (chunk & 0x7F) << 7;
+            if ((chunk & 0x80) == 0) return 2;
+            if (available == 2) throw EoF(this);
+
+            chunk = ioBuffer[readPos++];
+            value |= (chunk & 0x7F) << 14;
+            if ((chunk & 0x80) == 0) return 3;
+            if (available == 3) throw EoF(this);
+
+            chunk = ioBuffer[readPos++];
+            value |= (chunk & 0x7F) << 21;
+            if ((chunk & 0x80) == 0) return 4;
+            if (available == 4) throw EoF(this);
+
+            chunk = ioBuffer[readPos];
+            value |= chunk << 28; // can only use 4 bits from this chunk
+            if ((chunk & 0xF0) == 0) return 5;
+
+            if (trimNegative // allow for -ve values
+                && (chunk & 0xF0) == 0xF0
+                && available >= 10
+                    && ioBuffer[++readPos] == 0xFF
+                    && ioBuffer[++readPos] == 0xFF
+                    && ioBuffer[++readPos] == 0xFF
+                    && ioBuffer[++readPos] == 0xFF
+                    && ioBuffer[++readPos] == 0x01)
+            {
+                return 10;
+            }
+            throw AddErrorData(new OverflowException(), this);
+        }
+        private uint ReadUInt32Variant(bool trimNegative)
+        {
+            uint value;
+            int read = TryReadUInt32VariantWithoutMoving(trimNegative, out value);
+            if (read > 0)
+            {
+                ioIndex += read;
+                available -= read;
+                position += read;
+                return value;
+            }
+            throw EoF(this);
+        }
+        private bool TryReadUInt32Variant(out uint value)
+        {
+            int read = TryReadUInt32VariantWithoutMoving(false, out value);
+            if (read > 0)
+            {
+                ioIndex += read;
+                available -= read;
+                position += read;
+                return true;
+            }
+            return false;
+        }
+        /// <summary>
+        /// Reads an unsigned 32-bit integer from the stream; supported wire-types: Variant, Fixed32, Fixed64
+        /// </summary>
+        public uint ReadUInt32()
+        {
+            switch (wireType)
+            {
+                case WireType.Variant:
+                    return ReadUInt32Variant(false);
+                case WireType.Fixed32:
+                    if (available < 4) Ensure(4, true);
+                    position += 4;
+                    available -= 4;
+                    return ((uint)ioBuffer[ioIndex++])
+                        | (((uint)ioBuffer[ioIndex++]) << 8)
+                        | (((uint)ioBuffer[ioIndex++]) << 16)
+                        | (((uint)ioBuffer[ioIndex++]) << 24);
+                case WireType.Fixed64:
+                    ulong val = ReadUInt64();
+                    checked { return (uint)val; }
+                default:
+                    throw CreateWireTypeException();
+            }
+        }
+        
+        /// <summary>
+        /// Returns the position of the current reader (note that this is not necessarily the same as the position
+        /// in the underlying stream, if multiple readers are used on the same stream)
+        /// </summary>
+        public int Position { get { return position; } }
+        internal void Ensure(int count, bool strict)
+        {
+            Helpers.DebugAssert(available <= count, "Asking for data without checking first");
+            if (count > ioBuffer.Length)
+            {
+                BufferPool.ResizeAndFlushLeft(ref ioBuffer, count, ioIndex, available);
+                ioIndex = 0;
+            }
+            else if (ioIndex + count >= ioBuffer.Length)
+            {
+                // need to shift the buffer data to the left to make space
+                Helpers.BlockCopy(ioBuffer, ioIndex, ioBuffer, 0, available);
+                ioIndex = 0;
+            }
+            count -= available;
+            int writePos = ioIndex + available, bytesRead;
+            int canRead = ioBuffer.Length - writePos;
+            if (isFixedLength)
+            {   // throttle it if needed
+                if (dataRemaining < canRead) canRead = dataRemaining;
+            }
+            while (count > 0 && canRead > 0 && (bytesRead = source.Read(ioBuffer, writePos, canRead)) > 0)
+            {
+                available += bytesRead;
+                count -= bytesRead;
+                canRead -= bytesRead;
+                writePos += bytesRead;
+                if (isFixedLength) { dataRemaining -= bytesRead; }
+            }
+            if (strict && count > 0)
+            {
+                throw EoF(this);
+            }
+
+        }
+        /// <summary>
+        /// Reads a signed 16-bit integer from the stream: Variant, Fixed32, Fixed64, SignedVariant
+        /// </summary>
+        public short ReadInt16()
+        {
+            checked { return (short)ReadInt32(); }
+        }
+        /// <summary>
+        /// Reads an unsigned 16-bit integer from the stream; supported wire-types: Variant, Fixed32, Fixed64
+        /// </summary>
+        public ushort ReadUInt16()
+        {
+            checked { return (ushort)ReadUInt32(); }
+        }
+
+        /// <summary>
+        /// Reads an unsigned 8-bit integer from the stream; supported wire-types: Variant, Fixed32, Fixed64
+        /// </summary>
+        public byte ReadByte()
+        {
+            checked { return (byte)ReadUInt32(); }
+        }
+
+        /// <summary>
+        /// Reads a signed 8-bit integer from the stream; supported wire-types: Variant, Fixed32, Fixed64, SignedVariant
+        /// </summary>
+        public sbyte ReadSByte()
+        {
+            checked { return (sbyte)ReadInt32(); }
+        }
+
+        /// <summary>
+        /// Reads a signed 32-bit integer from the stream; supported wire-types: Variant, Fixed32, Fixed64, SignedVariant
+        /// </summary>
+        public int ReadInt32()
+        {
+            switch (wireType)
+            {
+                case WireType.Variant:
+                    return (int)ReadUInt32Variant(true);
+                case WireType.Fixed32:
+                    if (available < 4) Ensure(4, true);
+                    position += 4;
+                    available -= 4;
+                    return ((int)ioBuffer[ioIndex++])
+                        | (((int)ioBuffer[ioIndex++]) << 8)
+                        | (((int)ioBuffer[ioIndex++]) << 16)
+                        | (((int)ioBuffer[ioIndex++]) << 24);
+                case WireType.Fixed64:
+                    long l = ReadInt64();
+                    checked { return (int)l; }
+                case WireType.SignedVariant:
+                    return Zag(ReadUInt32Variant(true));
+                default:
+                    throw CreateWireTypeException();
+            }
+        }
+        private const long Int64Msb = ((long)1) << 63;
+        private const int Int32Msb = ((int)1) << 31;
+        private static int Zag(uint ziggedValue)
+        {
+            int value = (int)ziggedValue;
+            return (-(value & 0x01)) ^ ((value >> 1) & ~ProtoReader.Int32Msb);
+        }
+
+        private static long Zag(ulong ziggedValue)
+        {
+            long value = (long)ziggedValue;
+            return (-(value & 0x01L)) ^ ((value >> 1) & ~ProtoReader.Int64Msb);
+        }
+        /// <summary>
+        /// Reads a signed 64-bit integer from the stream; supported wire-types: Variant, Fixed32, Fixed64, SignedVariant
+        /// </summary>
+        public long ReadInt64()
+        {
+            switch (wireType)
+            {
+                case WireType.Variant:
+                    return (long)ReadUInt64Variant();
+                case WireType.Fixed32:
+                    return ReadInt32();
+                case WireType.Fixed64:
+                    if (available < 8) Ensure(8, true);
+                    position += 8;
+                    available -= 8;
+
+                    return ((long)ioBuffer[ioIndex++])
+                        | (((long)ioBuffer[ioIndex++]) << 8)
+                        | (((long)ioBuffer[ioIndex++]) << 16)
+                        | (((long)ioBuffer[ioIndex++]) << 24)
+                        | (((long)ioBuffer[ioIndex++]) << 32)
+                        | (((long)ioBuffer[ioIndex++]) << 40)
+                        | (((long)ioBuffer[ioIndex++]) << 48)
+                        | (((long)ioBuffer[ioIndex++]) << 56);
+
+                case WireType.SignedVariant:
+                    return Zag(ReadUInt64Variant());
+                default:
+                    throw CreateWireTypeException();
+            }
+        }
+
+        private int TryReadUInt64VariantWithoutMoving(out ulong value)
+        {
+            if (available < 10) Ensure(10, false);
+            if (available == 0)
+            {
+                value = 0;
+                return 0;
+            }
+            int readPos = ioIndex;
+            value = ioBuffer[readPos++];
+            if ((value & 0x80) == 0) return 1;
+            value &= 0x7F;
+            if (available == 1) throw EoF(this);
+
+            ulong chunk = ioBuffer[readPos++];
+            value |= (chunk & 0x7F) << 7;
+            if ((chunk & 0x80) == 0) return 2;
+            if (available == 2) throw EoF(this);
+
+            chunk = ioBuffer[readPos++];
+            value |= (chunk & 0x7F) << 14;
+            if ((chunk & 0x80) == 0) return 3;
+            if (available == 3) throw EoF(this);
+
+            chunk = ioBuffer[readPos++];
+            value |= (chunk & 0x7F) << 21;
+            if ((chunk & 0x80) == 0) return 4;
+            if (available == 4) throw EoF(this);
+
+            chunk = ioBuffer[readPos++];
+            value |= (chunk & 0x7F) << 28;
+            if ((chunk & 0x80) == 0) return 5;
+            if (available == 5) throw EoF(this);
+
+            chunk = ioBuffer[readPos++];
+            value |= (chunk & 0x7F) << 35;
+            if ((chunk & 0x80) == 0) return 6;
+            if (available == 6) throw EoF(this);
+
+            chunk = ioBuffer[readPos++];
+            value |= (chunk & 0x7F) << 42;
+            if ((chunk & 0x80) == 0) return 7;
+            if (available == 7) throw EoF(this);
+
+
+            chunk = ioBuffer[readPos++];
+            value |= (chunk & 0x7F) << 49;
+            if ((chunk & 0x80) == 0) return 8;
+            if (available == 8) throw EoF(this);
+
+            chunk = ioBuffer[readPos++];
+            value |= (chunk & 0x7F) << 56;
+            if ((chunk & 0x80) == 0) return 9;
+            if (available == 9) throw EoF(this);
+
+            chunk = ioBuffer[readPos];
+            value |= chunk << 63; // can only use 1 bit from this chunk
+
+            if ((chunk & ~(ulong)0x01) != 0) throw AddErrorData(new OverflowException(), this);
+            return 10;
+        }
+
+        private ulong ReadUInt64Variant()
+        {
+            ulong value;
+            int read = TryReadUInt64VariantWithoutMoving(out value);
+            if (read > 0)
+            {
+                ioIndex += read;
+                available -= read;
+                position += read;
+                return value;
+            }
+            throw EoF(this);
+        }
+
+#if NO_GENERICS
+        private System.Collections.Hashtable stringInterner;
+        private string Intern(string value)
+        {
+            if (value == null) return null;
+            if (value.Length == 0) return "";
+            if (stringInterner == null)
+            {
+                stringInterner = new System.Collections.Hashtable();
+                stringInterner.Add(value, value);      
+            }
+            else if (stringInterner.ContainsKey(value))
+            {
+                value = (string)stringInterner[value];
+            }
+            else
+            {
+                stringInterner.Add(value, value);
+            }
+            return value;
+        }
+#else
+        private System.Collections.Generic.Dictionary<string,string> stringInterner;
+                private string Intern(string value)
+        {
+            if (value == null) return null;
+            if (value.Length == 0) return "";
+            string found;
+            if (stringInterner == null)
+            {
+                stringInterner = new System.Collections.Generic.Dictionary<string, string>();
+                stringInterner.Add(value, value);        
+            }
+            else if (stringInterner.TryGetValue(value, out found))
+            {
+                value = found;
+            }
+            else
+            {
+                stringInterner.Add(value, value);
+            }
+            return value;
+        }
+#endif
+
+        static readonly UTF8Encoding encoding = new UTF8Encoding();
+        /// <summary>
+        /// Reads a string from the stream (using UTF8); supported wire-types: String
+        /// </summary>
+        public string ReadString()
+        {
+            if (wireType == WireType.String)
+            {
+                int bytes = (int)ReadUInt32Variant(false);
+                if (bytes == 0) return "";
+                if (available < bytes) Ensure(bytes, true);
+#if MF
+                byte[] tmp;
+                if(ioIndex == 0 && bytes == ioBuffer.Length) {
+                    // unlikely, but...
+                    tmp = ioBuffer;
+                } else {
+                    tmp = new byte[bytes];
+                    Helpers.BlockCopy(ioBuffer, ioIndex, tmp, 0, bytes);
+                }
+                string s = new string(encoding.GetChars(tmp));
+#else
+                string s = encoding.GetString(ioBuffer, ioIndex, bytes);
+#endif
+                if (internStrings) { s = Intern(s); }
+                available -= bytes;
+                position += bytes;
+                ioIndex += bytes;
+                return s;
+            }
+            throw CreateWireTypeException();
+        }
+        /// <summary>
+        /// Throws an exception indication that the given value cannot be mapped to an enum.
+        /// </summary>
+        public void ThrowEnumException(System.Type type, int value)
+        {
+            string desc = type == null ? "<null>" : type.FullName;
+            throw AddErrorData(new ProtoException("No " + desc + " enum is mapped to the wire-value " + value.ToString()), this);
+        }
+        private Exception CreateWireTypeException()
+        {
+            return CreateException("Invalid wire-type; this usually means you have over-written a file without truncating or setting the length; see http://stackoverflow.com/q/2152978/23354");
+        }
+        private Exception CreateException(string message)
+        {
+            return AddErrorData(new ProtoException(message), this);
+        }
+        /// <summary>
+        /// Reads a double-precision number from the stream; supported wire-types: Fixed32, Fixed64
+        /// </summary>
+        public
+#if !FEAT_SAFE
+ unsafe
+#endif
+ double ReadDouble()
+        {
+            switch (wireType)
+            {
+                case WireType.Fixed32:
+                    return ReadSingle();
+                case WireType.Fixed64:
+                    long value = ReadInt64();
+#if FEAT_SAFE
+                    return BitConverter.ToDouble(BitConverter.GetBytes(value), 0);
+#else
+                    return *(double*)&value;
+#endif
+                default:
+                    throw CreateWireTypeException();
+            }
+        }
+
+        /// <summary>
+        /// Reads (merges) a sub-message from the stream, internally calling StartSubItem and EndSubItem, and (in between)
+        /// parsing the message in accordance with the model associated with the reader
+        /// </summary>
+        public static object ReadObject(object value, int key, ProtoReader reader)
+        {
+#if FEAT_IKVM
+            throw new NotSupportedException();
+#else
+            return ReadTypedObject(value, key, reader, null);
+#endif
+        }
+#if !FEAT_IKVM
+        internal static object ReadTypedObject(object value, int key, ProtoReader reader, Type type)
+        {
+            if (reader.model == null)
+            {
+                throw AddErrorData(new InvalidOperationException("Cannot deserialize sub-objects unless a model is provided"), reader);
+            }
+            SubItemToken token = ProtoReader.StartSubItem(reader);
+            if (key >= 0)
+            {
+                value = reader.model.Deserialize(key, value, reader);
+            }
+            else if (type != null && reader.model.TryDeserializeAuxiliaryType(reader, DataFormat.Default, Serializer.ListItemTag, type, ref value, true, false, true, false))
+            {
+                // ok
+            }
+            else
+            {
+                TypeModel.ThrowUnexpectedType(type);
+            }
+            ProtoReader.EndSubItem(token, reader);
+            return value;
+        }
+#endif
+
+        /// <summary>
+        /// Makes the end of consuming a nested message in the stream; the stream must be either at the correct EndGroup
+        /// marker, or all fields of the sub-message must have been consumed (in either case, this means ReadFieldHeader
+        /// should return zero)
+        /// </summary>
+        public static void EndSubItem(SubItemToken token, ProtoReader reader)
+        {
+            if (reader == null) throw new ArgumentNullException("reader");
+            int value = token.value;
+            switch (reader.wireType)
+            {
+                case WireType.EndGroup:
+                    if (value >= 0) throw AddErrorData(new ArgumentException("token"), reader);
+                    if (-value != reader.fieldNumber) throw reader.CreateException("Wrong group was ended"); // wrong group ended!
+                    reader.wireType = WireType.None; // this releases ReadFieldHeader
+                    reader.depth--;
+                    break;
+                // case WireType.None: // TODO reinstate once reads reset the wire-type
+                default:
+                    if (value < reader.position) throw reader.CreateException("Sub-message not read entirely");
+                    if (reader.blockEnd != reader.position && reader.blockEnd != int.MaxValue)
+                    {
+                        throw reader.CreateException("Sub-message not read correctly");
+                    }
+                    reader.blockEnd = value;
+                    reader.depth--;
+                    break;
+                /*default:
+                    throw reader.BorkedIt(); */
+            }
+        }
+
+        /// <summary>
+        /// Begins consuming a nested message in the stream; supported wire-types: StartGroup, String
+        /// </summary>
+        /// <remarks>The token returned must be help and used when callining EndSubItem</remarks>
+        public static SubItemToken StartSubItem(ProtoReader reader)
+        {
+            if (reader == null) throw new ArgumentNullException("reader");
+            switch (reader.wireType)
+            {
+                case WireType.StartGroup:
+                    reader.wireType = WireType.None; // to prevent glitches from double-calling
+                    reader.depth++;
+                    return new SubItemToken(-reader.fieldNumber);
+                case WireType.String:
+                    int len = (int)reader.ReadUInt32Variant(false);
+                    if (len < 0) throw AddErrorData(new InvalidOperationException(), reader);
+                    int lastEnd = reader.blockEnd;
+                    reader.blockEnd = reader.position + len;
+                    reader.depth++;
+                    return new SubItemToken(lastEnd);
+                default:
+                    throw reader.CreateWireTypeException(); // throws
+            }
+        }
+
+        /// <summary>
+        /// Reads a field header from the stream, setting the wire-type and retuning the field number. If no
+        /// more fields are available, then 0 is returned. This methods respects sub-messages.
+        /// </summary>
+        public int ReadFieldHeader()
+        {
+            // at the end of a group the caller must call EndSubItem to release the
+            // reader (which moves the status to Error, since ReadFieldHeader must
+            // then be called)
+            if (blockEnd <= position || wireType == WireType.EndGroup) { return 0; }
+            uint tag;
+            if (TryReadUInt32Variant(out tag))
+            {
+                wireType = (WireType)(tag & 7);
+                fieldNumber = (int)(tag >> 3);
+                if(fieldNumber < 1) throw new ProtoException("Invalid field in source data: " + fieldNumber.ToString());
+            }
+            else
+            {
+                wireType = WireType.None;
+                fieldNumber = 0;
+            }
+            if (wireType == ProtoBuf.WireType.EndGroup)
+            {
+                if (depth > 0) return 0; // spoof an end, but note we still set the field-number
+                throw new ProtoException("Unexpected end-group in source data; this usually means the source data is corrupt");
+            }
+            return fieldNumber;
+        }
+        /// <summary>
+        /// Looks ahead to see whether the next field in the stream is what we expect
+        /// (typically; what we've just finished reading - for example ot read successive list items)
+        /// </summary>
+        public bool TryReadFieldHeader(int field)
+        {
+            // check for virtual end of stream
+            if (blockEnd <= position || wireType == WireType.EndGroup) { return false; }
+            uint tag;
+            int read = TryReadUInt32VariantWithoutMoving(false, out tag);
+            WireType tmpWireType; // need to catch this to exclude (early) any "end group" tokens
+            if (read > 0 && ((int)tag >> 3) == field
+                && (tmpWireType = (WireType)(tag & 7)) != WireType.EndGroup)
+            {
+                wireType = tmpWireType;
+                fieldNumber = field;
+                position += read;
+                ioIndex += read;
+                available -= read;
+                return true;
+            }
+            return false;
+        }
+
+        /// <summary>
+        /// Get the TypeModel associated with this reader
+        /// </summary>
+        public TypeModel Model { get { return model; } }
+
+        /// <summary>
+        /// Compares the streams current wire-type to the hinted wire-type, updating the reader if necessary; for example,
+        /// a Variant may be updated to SignedVariant. If the hinted wire-type is unrelated then no change is made.
+        /// </summary>
+        public void Hint(WireType wireType)
+        {
+            if (this.wireType == wireType) { }  // fine; everything as we expect
+            else if (((int)wireType & 7) == (int)this.wireType)
+            {   // the underling type is a match; we're customising it with an extension
+                this.wireType = wireType;
+            }
+            // note no error here; we're OK about using alternative data
+        }
+
+        /// <summary>
+        /// Verifies that the stream's current wire-type is as expected, or a specialized sub-type (for example,
+        /// SignedVariant) - in which case the current wire-type is updated. Otherwise an exception is thrown.
+        /// </summary>
+        public void Assert(WireType wireType)
+        {
+            if (this.wireType == wireType) { }  // fine; everything as we expect
+            else if (((int)wireType & 7) == (int)this.wireType)
+            {   // the underling type is a match; we're customising it with an extension
+                this.wireType = wireType;
+            }
+            else
+            {   // nope; that is *not* what we were expecting!
+                throw CreateWireTypeException();
+            }
+        }
+
+        /// <summary>
+        /// Discards the data for the current field.
+        /// </summary>
+        public void SkipField()
+        {
+            switch (wireType)
+            {
+                case WireType.Fixed32:
+                    if(available < 4) Ensure(4, true);
+                    available -= 4;
+                    ioIndex += 4;
+                    position += 4;
+                    return;
+                case WireType.Fixed64:
+                    if (available < 8) Ensure(8, true);
+                    available -= 8;
+                    ioIndex += 8;
+                    position += 8;
+                    return;
+                case WireType.String:
+                    int len = (int)ReadUInt32Variant(false);
+                    if (len <= available)
+                    { // just jump it!
+                        available -= len;
+                        ioIndex += len;
+                        position += len;
+                        return;
+                    }
+                    // everything remaining in the buffer is garbage
+                    position += len; // assumes success, but if it fails we're screwed anyway
+                    len -= available; // discount anything we've got to-hand
+                    ioIndex = available = 0; // note that we have no data in the buffer
+                    if (isFixedLength)
+                    {
+                        if (len > dataRemaining) throw EoF(this);
+                        // else assume we're going to be OK
+                        dataRemaining -= len;
+                    }
+                    ProtoReader.Seek(source, len, ioBuffer);
+                    return;
+                case WireType.Variant:
+                case WireType.SignedVariant:
+                    ReadUInt64Variant(); // and drop it
+                    return;
+                case WireType.StartGroup:
+                    int originalFieldNumber = this.fieldNumber;
+                    depth++; // need to satisfy the sanity-checks in ReadFieldHeader
+                    while (ReadFieldHeader() > 0) { SkipField(); }
+                    depth--;
+                    if (wireType == WireType.EndGroup && fieldNumber == originalFieldNumber)
+                    { // we expect to exit in a similar state to how we entered
+                        wireType = ProtoBuf.WireType.None;
+                        return;
+                    }
+                    throw CreateWireTypeException();
+                case WireType.None: // treat as explicit errorr
+                case WireType.EndGroup: // treat as explicit error
+                default: // treat as implicit error
+                    throw CreateWireTypeException();
+            }
+        }
+
+        /// <summary>
+        /// Reads an unsigned 64-bit integer from the stream; supported wire-types: Variant, Fixed32, Fixed64
+        /// </summary>
+        public ulong ReadUInt64()
+        {
+            switch (wireType)
+            {
+                case WireType.Variant:
+                    return ReadUInt64Variant();
+                case WireType.Fixed32:
+                    return ReadUInt32();
+                case WireType.Fixed64:
+                    if (available < 8) Ensure(8, true);
+                    position += 8;
+                    available -= 8;
+
+                    return ((ulong)ioBuffer[ioIndex++])
+                        | (((ulong)ioBuffer[ioIndex++]) << 8)
+                        | (((ulong)ioBuffer[ioIndex++]) << 16)
+                        | (((ulong)ioBuffer[ioIndex++]) << 24)
+                        | (((ulong)ioBuffer[ioIndex++]) << 32)
+                        | (((ulong)ioBuffer[ioIndex++]) << 40)
+                        | (((ulong)ioBuffer[ioIndex++]) << 48)
+                        | (((ulong)ioBuffer[ioIndex++]) << 56);
+                default:
+                    throw CreateWireTypeException();
+            }
+        }
+        /// <summary>
+        /// Reads a single-precision number from the stream; supported wire-types: Fixed32, Fixed64
+        /// </summary>
+        public
+#if !FEAT_SAFE
+ unsafe
+#endif
+ float ReadSingle()
+        {
+            switch (wireType)
+            {
+                case WireType.Fixed32:
+                    {
+                        int value = ReadInt32();
+#if FEAT_SAFE
+                        return BitConverter.ToSingle(BitConverter.GetBytes(value), 0);
+#else
+                        return *(float*)&value;
+#endif
+                    }
+                case WireType.Fixed64:
+                    {
+                        double value = ReadDouble();
+                        float f = (float)value;
+                        if (Helpers.IsInfinity(f)
+                            && !Helpers.IsInfinity(value))
+                        {
+                            throw AddErrorData(new OverflowException(), this);
+                        }
+                        return f;
+                    }
+                default:
+                    throw CreateWireTypeException();
+            }
+        }
+
+        /// <summary>
+        /// Reads a boolean value from the stream; supported wire-types: Variant, Fixed32, Fixed64
+        /// </summary>
+        /// <returns></returns>
+        public bool ReadBoolean()
+        {
+            switch (ReadUInt32())
+            {
+                case 0: return false;
+                case 1: return true;
+                default: throw CreateException("Unexpected boolean value");
+            }
+        }
+
+        private static readonly byte[] EmptyBlob = new byte[0];
+        /// <summary>
+        /// Reads a byte-sequence from the stream, appending them to an existing byte-sequence (which can be null); supported wire-types: String
+        /// </summary>
+        public static byte[] AppendBytes(byte[] value, ProtoReader reader)
+        {
+            if (reader == null) throw new ArgumentNullException("reader");
+            switch (reader.wireType)
+            {
+                case WireType.String:
+                    int len = (int)reader.ReadUInt32Variant(false);
+                    reader.wireType = WireType.None;
+                    if (len == 0) return value == null ? EmptyBlob : value;
+                    int offset;
+                    if (value == null || value.Length == 0)
+                    {
+                        offset = 0;
+                        value = new byte[len];
+                    }
+                    else
+                    {
+                        offset = value.Length;
+                        byte[] tmp = new byte[value.Length + len];
+                        Helpers.BlockCopy(value, 0, tmp, 0, value.Length);
+                        value = tmp;
+                    }
+                    // value is now sized with the final length, and (if necessary)
+                    // contains the old data up to "offset"
+                    reader.position += len; // assume success
+                    while (len > reader.available)
+                    {
+                        if (reader.available > 0)
+                        {
+                            // copy what we *do* have
+                            Helpers.BlockCopy(reader.ioBuffer, reader.ioIndex, value, offset, reader.available);
+                            len -= reader.available;
+                            offset += reader.available;
+                            reader.ioIndex = reader.available = 0; // we've drained the buffer
+                        }
+                        //  now refill the buffer (without overflowing it)
+                        int count = len > reader.ioBuffer.Length ? reader.ioBuffer.Length : len;
+                        if (count > 0) reader.Ensure(count, true);
+                    }
+                    // at this point, we know that len <= available
+                    if (len > 0)
+                    {   // still need data, but we have enough buffered
+                        Helpers.BlockCopy(reader.ioBuffer, reader.ioIndex, value, offset, len);
+                        reader.ioIndex += len;
+                        reader.available -= len;
+                    }
+                    return value;
+                default:
+                    throw reader.CreateWireTypeException();
+            }
+        }
+
+        //static byte[] ReadBytes(Stream stream, int length)
+        //{
+        //    if (stream == null) throw new ArgumentNullException("stream");
+        //    if (length < 0) throw new ArgumentOutOfRangeException("length");
+        //    byte[] buffer = new byte[length];
+        //    int offset = 0, read;
+        //    while (length > 0 && (read = stream.Read(buffer, offset, length)) > 0)
+        //    {
+        //        length -= read;
+        //    }
+        //    if (length > 0) throw EoF(null);
+        //    return buffer;
+        //}
+        private static int ReadByteOrThrow(Stream source)
+        {
+            int val = source.ReadByte();
+            if (val < 0) throw EoF(null);
+            return val;
+        }
+        /// <summary>
+        /// Reads the length-prefix of a message from a stream without buffering additional data, allowing a fixed-length
+        /// reader to be created.
+        /// </summary>
+        public static int ReadLengthPrefix(Stream source, bool expectHeader, PrefixStyle style, out int fieldNumber)
+        {
+            int bytesRead;
+            return ReadLengthPrefix(source, expectHeader, style, out fieldNumber, out bytesRead);
+        }
+        /// <summary>
+        /// Reads a little-endian encoded integer. An exception is thrown if the data is not all available.
+        /// </summary>
+        public static int DirectReadLittleEndianInt32(Stream source)
+        {
+            return ReadByteOrThrow(source)
+                | (ReadByteOrThrow(source) << 8)
+                | (ReadByteOrThrow(source) << 16)
+                | (ReadByteOrThrow(source) << 24);
+        }
+        /// <summary>
+        /// Reads a big-endian encoded integer. An exception is thrown if the data is not all available.
+        /// </summary>
+        public static int DirectReadBigEndianInt32(Stream source)
+        {
+            return (ReadByteOrThrow(source) << 24)
+                 | (ReadByteOrThrow(source) << 16)
+                 | (ReadByteOrThrow(source) << 8)
+                 | ReadByteOrThrow(source);
+        }
+        /// <summary>
+        /// Reads a varint encoded integer. An exception is thrown if the data is not all available.
+        /// </summary>
+        public static int DirectReadVarintInt32(Stream source)
+        {
+            uint val;
+            int bytes = TryReadUInt32Variant(source, out val);
+            if (bytes <= 0) throw EoF(null);
+            return (int) val;
+        }
+        /// <summary>
+        /// Reads a string (of a given lenth, in bytes) directly from the source into a pre-existing buffer. An exception is thrown if the data is not all available.
+        /// </summary>
+        public static void DirectReadBytes(Stream source, byte[] buffer, int offset, int count)
+        {
+            int read;
+            if (source == null) throw new ArgumentNullException("source");
+            while(count > 0 && (read = source.Read(buffer, offset, count)) > 0)
+            {
+                count -= read;
+                offset += read;
+            }
+            if (count > 0) throw EoF(null);
+        }
+        /// <summary>
+        /// Reads a given number of bytes directly from the source. An exception is thrown if the data is not all available.
+        /// </summary>
+        public static byte[] DirectReadBytes(Stream source, int count)
+        {
+            byte[] buffer = new byte[count];
+            DirectReadBytes(source, buffer, 0, count);
+            return buffer;
+        }
+        /// <summary>
+        /// Reads a string (of a given lenth, in bytes) directly from the source. An exception is thrown if the data is not all available.
+        /// </summary>
+        public static string DirectReadString(Stream source, int length)
+        {
+            byte[] buffer = new byte[length];
+            DirectReadBytes(source, buffer, 0, length);
+            return Encoding.UTF8.GetString(buffer, 0, length);
+        }
+
+        /// <summary>
+        /// Reads the length-prefix of a message from a stream without buffering additional data, allowing a fixed-length
+        /// reader to be created.
+        /// </summary>
+        public static int ReadLengthPrefix(Stream source, bool expectHeader, PrefixStyle style, out int fieldNumber, out int bytesRead)
+        {
+            fieldNumber = 0;
+            switch (style)
+            {
+                case PrefixStyle.None:
+                    bytesRead = 0;
+                    return int.MaxValue;
+                case PrefixStyle.Base128:
+                    uint val;
+                    int tmpBytesRead;
+                    bytesRead = 0;
+                    if (expectHeader)
+                    {
+                        tmpBytesRead = ProtoReader.TryReadUInt32Variant(source, out val);
+                        bytesRead += tmpBytesRead;
+                        if (tmpBytesRead > 0)
+                        {
+                            if ((val & 7) != (uint)WireType.String)
+                            { // got a header, but it isn't a string
+                                throw new InvalidOperationException();
+                            }
+                            fieldNumber = (int)(val >> 3);
+                            tmpBytesRead = ProtoReader.TryReadUInt32Variant(source, out val);
+                            bytesRead += tmpBytesRead;
+                            if (bytesRead == 0)
+                            { // got a header, but no length
+                                throw EoF(null);
+                            }
+                            return (int)val;
+                        }
+                        else
+                        { // no header
+                            bytesRead = 0;
+                            return -1;
+                        }
+                    }
+                    // check for a length
+                    tmpBytesRead = ProtoReader.TryReadUInt32Variant(source, out val);
+                    bytesRead += tmpBytesRead;
+                    return bytesRead < 0 ? -1 : (int)val;
+
+                case PrefixStyle.Fixed32:
+                    {
+                        int b = source.ReadByte();
+                        if (b < 0)
+                        {
+                            bytesRead = 0;
+                            return -1;
+                        }
+                        bytesRead = 4;
+                        return b
+                             | (ReadByteOrThrow(source) << 8)
+                             | (ReadByteOrThrow(source) << 16)
+                             | (ReadByteOrThrow(source) << 24);
+                    }
+                case PrefixStyle.Fixed32BigEndian:
+                    {
+                        int b = source.ReadByte();
+                        if (b < 0)
+                        {
+                            bytesRead = 0;
+                            return -1;
+                        }
+                        bytesRead = 4;
+                        return (b << 24)
+                            | (ReadByteOrThrow(source) << 16)
+                            | (ReadByteOrThrow(source) << 8)
+                            | ReadByteOrThrow(source);
+                    }
+                default:
+                    throw new ArgumentOutOfRangeException("style");
+            }
+        }
+        /// <returns>The number of bytes consumed; 0 if no data available</returns>
+        private static int TryReadUInt32Variant(Stream source, out uint value)
+        {
+            value = 0;
+            int b = source.ReadByte();
+            if (b < 0) { return 0; }
+            value = (uint)b;
+            if ((value & 0x80) == 0) { return 1; }
+            value &= 0x7F;
+
+            b = source.ReadByte();
+            if (b < 0) throw EoF(null);
+            value |= ((uint)b & 0x7F) << 7;
+            if ((b & 0x80) == 0) return 2;
+
+            b = source.ReadByte();
+            if (b < 0) throw EoF(null);
+            value |= ((uint)b & 0x7F) << 14;
+            if ((b & 0x80) == 0) return 3;
+
+            b = source.ReadByte();
+            if (b < 0) throw EoF(null);
+            value |= ((uint)b & 0x7F) << 21;
+            if ((b & 0x80) == 0) return 4;
+
+            b = source.ReadByte();
+            if (b < 0) throw EoF(null);
+            value |= (uint)b << 28; // can only use 4 bits from this chunk
+            if ((b & 0xF0) == 0) return 5;
+
+            throw new OverflowException();
+        }
+
+        internal static void Seek(Stream source, int count, byte[] buffer)
+        {
+            if (source.CanSeek)
+            {
+                source.Seek(count, SeekOrigin.Current);
+                count = 0;
+            }
+            else if (buffer != null)
+            {
+                int bytesRead;
+                while (count > buffer.Length && (bytesRead = source.Read(buffer, 0, buffer.Length)) > 0)
+                {
+                    count -= bytesRead;
+                }
+                while (count > 0 && (bytesRead = source.Read(buffer, 0, count)) > 0)
+                {
+                    count -= bytesRead;
+                }
+            }
+            else // borrow a buffer
+            {
+                buffer = BufferPool.GetBuffer();
+                try
+                {
+                    int bytesRead;
+                    while (count > buffer.Length && (bytesRead = source.Read(buffer, 0, buffer.Length)) > 0)
+                    {
+                        count -= bytesRead;
+                    }
+                    while (count > 0 && (bytesRead = source.Read(buffer, 0, count)) > 0)
+                    {
+                        count -= bytesRead;
+                    }
+                }
+                finally
+                {
+                    BufferPool.ReleaseBufferToPool(ref buffer);
+                }
+            }
+            if (count > 0) throw EoF(null);
+        }
+        internal static Exception AddErrorData(Exception exception, ProtoReader source)
+        {
+#if !CF && !FX11 && !PORTABLE
+            if (exception != null && source != null && !exception.Data.Contains("protoSource"))
+            {
+                exception.Data.Add("protoSource", string.Format("tag={0}; wire-type={1}; offset={2}; depth={3}",
+                    source.fieldNumber, source.wireType, source.position, source.depth));
+            }
+#endif
+            return exception;
+
+        }
+        private static Exception EoF(ProtoReader source)
+        {
+            return AddErrorData(new EndOfStreamException(), source);
+        }
+
+        /// <summary>
+        /// Copies the current field into the instance as extension data
+        /// </summary>
+        public void AppendExtensionData(IExtensible instance)
+        {
+            if (instance == null) throw new ArgumentNullException("instance");
+            IExtension extn = instance.GetExtensionObject(true);
+            bool commit = false;
+            // unusually we *don't* want "using" here; the "finally" does that, with
+            // the extension object being responsible for disposal etc
+            Stream dest = extn.BeginAppend();
+            try
+            {
+                //TODO: replace this with stream-based, buffered raw copying
+                using (ProtoWriter writer = new ProtoWriter(dest, model, null))
+                {
+                    AppendExtensionField(writer);
+                    writer.Close();
+                }
+                commit = true;
+            }
+            finally { extn.EndAppend(dest, commit); }
+        }
+        private void AppendExtensionField(ProtoWriter writer)
+        {
+            //TODO: replace this with stream-based, buffered raw copying
+            ProtoWriter.WriteFieldHeader(fieldNumber, wireType, writer);
+            switch (wireType)
+            {
+                case WireType.Fixed32:
+                    ProtoWriter.WriteInt32(ReadInt32(), writer);
+                    return;
+                case WireType.Variant:
+                case WireType.SignedVariant:
+                case WireType.Fixed64:
+                    ProtoWriter.WriteInt64(ReadInt64(), writer);
+                    return;
+                case WireType.String:
+                    ProtoWriter.WriteBytes(AppendBytes(null, this), writer);
+                    return;
+                case WireType.StartGroup:
+                    SubItemToken readerToken = StartSubItem(this),
+                        writerToken = ProtoWriter.StartSubItem(null, writer);
+                    while (ReadFieldHeader() > 0) { AppendExtensionField(writer); }
+                    EndSubItem(readerToken, this);
+                    ProtoWriter.EndSubItem(writerToken, writer);
+                    return;
+                case WireType.None: // treat as explicit errorr
+                case WireType.EndGroup: // treat as explicit error
+                default: // treat as implicit error
+                    throw CreateWireTypeException();
+            }
+        }
+        /// <summary>
+        /// Indicates whether the reader still has data remaining in the current sub-item,
+        /// additionally setting the wire-type for the next field if there is more data.
+        /// This is used when decoding packed data.
+        /// </summary>
+        public static bool HasSubValue(ProtoBuf.WireType wireType, ProtoReader source)
+        {
+            if (source == null) throw new ArgumentNullException("source");
+            // check for virtual end of stream
+            if (source.blockEnd <= source.position || wireType == WireType.EndGroup) { return false; }
+            source.wireType = wireType;
+            return true;
+        }
+
+        internal int GetTypeKey(ref Type type)
+        {
+            return model.GetKey(ref type);
+        }
+
+        internal NetObjectCache NetCache
+        {
+            get { return netCache; }
+        }
+
+        internal System.Type DeserializeType(string value)
+        {
+            return TypeModel.DeserializeType(model, value);
+        }
+
+        internal void SetRootObject(object value)
+        {
+            netCache.SetKeyedObject(NetObjectCache.Root, value);
+            trapCount--;
+        }
+
+        
+        /// <summary>
+        /// Utility method, not intended for public use; this helps maintain the root object is complex scenarios
+        /// </summary>
+        public static void NoteObject(object value, ProtoReader reader)
+        {
+            if (reader == null) throw new ArgumentNullException("reader");
+            if(reader.trapCount != 0)
+            {
+                reader.netCache.RegisterTrappedObject(value);
+                reader.trapCount--;
+            }
+        }
+
+        /// <summary>
+        /// Reads a Type from the stream, using the model's DynamicTypeFormatting if appropriate; supported wire-types: String
+        /// </summary>
+        public System.Type ReadType()
+        {
+            return TypeModel.DeserializeType(model, ReadString());
+        }
+
+        internal void TrapNextObject(int newObjectKey)
+        {
+            trapCount++;
+            netCache.SetKeyedObject(newObjectKey, null); // use null as a temp
+        }
+
+        internal void CheckFullyConsumed()
+        {
+            if (isFixedLength)
+            {
+                if (dataRemaining != 0) throw new ProtoException("Incorrect number of bytes consumed");
+            }
+            else
+            {
+                if (available != 0) throw new ProtoException("Unconsumed data left in the buffer; this suggests corrupt input");
+            }
+        }
+
+        /// <summary>
+        /// Merge two objects using the details from the current reader; this is used to change the type
+        /// of objects when an inheritance relationship is discovered later than usual during deserilazation.
+        /// </summary>
+        public static object Merge(ProtoReader parent, object from, object to)
+        {
+            if (parent == null) throw new ArgumentNullException("parent");
+            TypeModel model = parent.Model;
+            SerializationContext ctx = parent.Context;
+            if(model == null) throw new InvalidOperationException("Types cannot be merged unless a type-model has been specified");
+            using (MemoryStream ms = new MemoryStream())
+            {
+                model.Serialize(ms, from, ctx);
+                ms.Position = 0;
+                return model.Deserialize(ms, to, null);
+            }
+        }
+
+#region RECYCLER
+
+        internal static ProtoReader Create(Stream source, TypeModel model, SerializationContext context, int len)
+        {
+            ProtoReader reader = GetRecycled();
+            if (reader == null)
+            {
+                return new ProtoReader(source, model, context, len);
+            }
+            Init(reader, source, model, context, len);
+            return reader;
+        }
+
+#if !PLAT_NO_THREADSTATIC
+        [ThreadStatic]
+        private static ProtoReader lastReader;
+
+        private static ProtoReader GetRecycled()
+        {
+            ProtoReader tmp = lastReader;
+            lastReader = null;
+            return tmp;
+        }
+        internal static void Recycle(ProtoReader reader)
+        {
+            if(reader != null)
+            {
+                reader.Dispose();
+                lastReader = reader;
+            }
+        }
+#elif !PLAT_NO_INTERLOCKED
+        private static object lastReader;
+        private static ProtoReader GetRecycled()
+        {
+            return (ProtoReader)System.Threading.Interlocked.Exchange(ref lastReader, null);
+        }
+        internal static void Recycle(ProtoReader reader)
+        {
+            if(reader != null)
+            {
+                reader.Dispose();
+                System.Threading.Interlocked.Exchange(ref lastReader, reader);
+            }
+        }
+#else
+        private static readonly object recycleLock = new object();
+        private static ProtoReader lastReader;
+        private static ProtoReader GetRecycled()
+        {
+            lock(recycleLock)
+            {
+                ProtoReader tmp = lastReader;
+                lastReader = null;
+                return tmp;
+            }            
+        }
+        internal static void Recycle(ProtoReader reader)
+        {
+            if(reader != null)
+            {
+                reader.Dispose();
+                lock(recycleLock)
+                {
+                    lastReader = reader;
+                }
+            }
+        }
+#endif
+
+#endregion
+    }
+}

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/ProtoReader.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: f5a1b8dcb64d6a942a56b9b60f5042af
+timeCreated: 1515899114
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 951 - 0
Unity/Assets/Plugins/protobuf-net/ProtoWriter.cs

@@ -0,0 +1,951 @@
+using System;
+
+using System.IO;
+using System.Text;
+using ProtoBuf.Meta;
+#if MF
+using OverflowException = System.ApplicationException;
+#endif
+
+#if FEAT_IKVM
+using Type = IKVM.Reflection.Type;
+#endif
+
+namespace ProtoBuf
+{
+    /// <summary>
+    /// Represents an output stream for writing protobuf data.
+    /// 
+    /// Why is the API backwards (static methods with writer arguments)?
+    /// See: http://marcgravell.blogspot.com/2010/03/last-will-be-first-and-first-will-be.html
+    /// </summary>
+    public sealed class ProtoWriter : IDisposable
+    {
+        private Stream dest;
+        TypeModel model;
+        /// <summary>
+        /// Write an encapsulated sub-object, using the supplied unique key (reprasenting a type).
+        /// </summary>
+        /// <param name="value">The object to write.</param>
+        /// <param name="key">The key that uniquely identifies the type within the model.</param>
+        /// <param name="writer">The destination.</param>
+        public static void WriteObject(object value, int key, ProtoWriter writer)
+        {
+#if FEAT_IKVM
+            throw new NotSupportedException();
+#else
+            if (writer == null) throw new ArgumentNullException("writer");
+            if (writer.model == null)
+            {
+                throw new InvalidOperationException("Cannot serialize sub-objects unless a model is provided");
+            }
+
+            SubItemToken token = StartSubItem(value, writer);
+            if (key >= 0)
+            {
+                writer.model.Serialize(key, value, writer);
+            }
+            else if (writer.model != null && writer.model.TrySerializeAuxiliaryType(writer, value.GetType(), DataFormat.Default, Serializer.ListItemTag, value, false))
+            {
+                // all ok
+            }
+            else
+            {
+                TypeModel.ThrowUnexpectedType(value.GetType());
+            }
+            EndSubItem(token, writer);
+#endif 
+        }
+        /// <summary>
+        /// Write an encapsulated sub-object, using the supplied unique key (reprasenting a type) - but the
+        /// caller is asserting that this relationship is non-recursive; no recursion check will be
+        /// performed.
+        /// </summary>
+        /// <param name="value">The object to write.</param>
+        /// <param name="key">The key that uniquely identifies the type within the model.</param>
+        /// <param name="writer">The destination.</param>
+        public static void WriteRecursionSafeObject(object value, int key, ProtoWriter writer)
+        {
+            if (writer == null) throw new ArgumentNullException("writer");
+            if (writer.model == null)
+            {
+                throw new InvalidOperationException("Cannot serialize sub-objects unless a model is provided");
+            }
+            SubItemToken token = StartSubItem(null, writer);
+            writer.model.Serialize(key, value, writer);
+            EndSubItem(token, writer);
+        }
+        internal static void WriteObject(object value, int key, ProtoWriter writer, PrefixStyle style, int fieldNumber)
+        {
+#if FEAT_IKVM
+            throw new NotSupportedException();
+#else
+            if (writer.model == null)
+            {
+                throw new InvalidOperationException("Cannot serialize sub-objects unless a model is provided");
+            }
+            if (writer.wireType != WireType.None) throw ProtoWriter.CreateException(writer);
+
+            switch (style)
+            {
+                case PrefixStyle.Base128:
+                    writer.wireType = WireType.String;
+                    writer.fieldNumber = fieldNumber;
+                    if (fieldNumber > 0) WriteHeaderCore(fieldNumber, WireType.String, writer);
+                    break;
+                case PrefixStyle.Fixed32:
+                case PrefixStyle.Fixed32BigEndian:
+                    writer.fieldNumber = 0;
+                    writer.wireType = WireType.Fixed32;
+                    break;
+                default:
+                    throw new ArgumentOutOfRangeException("style");
+            }
+            SubItemToken token = StartSubItem(value, writer, true);
+            if (key < 0)
+            {
+                if (!writer.model.TrySerializeAuxiliaryType(writer, value.GetType(), DataFormat.Default, Serializer.ListItemTag, value, false))
+                {
+                    TypeModel.ThrowUnexpectedType(value.GetType());
+                }
+            }
+            else
+            {
+                writer.model.Serialize(key, value, writer);
+            }
+            EndSubItem(token, writer, style);
+#endif       
+        }
+
+        internal int GetTypeKey(ref Type type)
+        {
+            return model.GetKey(ref type);
+        }
+        
+        private readonly NetObjectCache netCache = new NetObjectCache();
+        internal NetObjectCache NetCache
+        {
+            get { return netCache;}
+        }
+
+        private int fieldNumber, flushLock;
+        WireType wireType;
+        internal WireType WireType { get { return wireType; } }
+        /// <summary>
+        /// Writes a field-header, indicating the format of the next data we plan to write.
+        /// </summary>
+        public static void WriteFieldHeader(int fieldNumber, WireType wireType, ProtoWriter writer) {
+            if (writer == null) throw new ArgumentNullException("writer");
+            if (writer.wireType != WireType.None) throw new InvalidOperationException("Cannot write a " + wireType.ToString()
+                + " header until the " + writer.wireType.ToString() + " data has been written");
+            if(fieldNumber < 0) throw new ArgumentOutOfRangeException("fieldNumber");
+#if DEBUG
+            switch (wireType)
+            {   // validate requested header-type
+                case WireType.Fixed32:
+                case WireType.Fixed64:
+                case WireType.String:
+                case WireType.StartGroup:
+                case WireType.SignedVariant:
+                case WireType.Variant:
+                    break; // fine
+                case WireType.None:
+                case WireType.EndGroup:
+                default:
+                    throw new ArgumentException("Invalid wire-type: " + wireType.ToString(), "wireType");                
+            }
+#endif
+            if (writer.packedFieldNumber == 0) {
+                writer.fieldNumber = fieldNumber;
+                writer.wireType = wireType;
+                WriteHeaderCore(fieldNumber, wireType, writer);
+            }
+            else if (writer.packedFieldNumber == fieldNumber)
+            { // we'll set things up, but note we *don't* actually write the header here
+                switch (wireType)
+                {
+                    case WireType.Fixed32:
+                    case WireType.Fixed64:
+                    case WireType.Variant:
+                    case WireType.SignedVariant:
+                        break; // fine
+                    default:
+                        throw new InvalidOperationException("Wire-type cannot be encoded as packed: " + wireType.ToString());
+                }
+                writer.fieldNumber = fieldNumber;
+                writer.wireType = wireType;
+            }
+            else
+            {
+                throw new InvalidOperationException("Field mismatch during packed encoding; expected " + writer.packedFieldNumber.ToString() + " but received " + fieldNumber.ToString());
+            }
+        }
+        internal static void WriteHeaderCore(int fieldNumber, WireType wireType, ProtoWriter writer)
+        {
+            uint header = (((uint)fieldNumber) << 3)
+                | (((uint)wireType) & 7);
+            WriteUInt32Variant(header, writer);
+        }
+
+        /// <summary>
+        /// Writes a byte-array to the stream; supported wire-types: String
+        /// </summary>
+        public static void WriteBytes(byte[] data, ProtoWriter writer)
+        {
+            if (data == null) throw new ArgumentNullException("data");
+            ProtoWriter.WriteBytes(data, 0, data.Length, writer);
+        }
+        /// <summary>
+        /// Writes a byte-array to the stream; supported wire-types: String
+        /// </summary>
+        public static void WriteBytes(byte[] data, int offset, int length, ProtoWriter writer)
+        {
+            if (data == null) throw new ArgumentNullException("data");
+            if (writer == null) throw new ArgumentNullException("writer");
+            switch (writer.wireType)
+            {
+                case WireType.Fixed32:
+                    if (length != 4) throw new ArgumentException("length");
+                    goto CopyFixedLength;  // ugly but effective
+                case WireType.Fixed64:
+                    if (length != 8) throw new ArgumentException("length");
+                    goto CopyFixedLength;  // ugly but effective
+                case WireType.String:
+                    WriteUInt32Variant((uint)length, writer);
+                    writer.wireType = WireType.None;
+                    if (length == 0) return;
+                    if (writer.flushLock != 0 || length <= writer.ioBuffer.Length) // write to the buffer
+                    {
+                        goto CopyFixedLength; // ugly but effective
+                    }
+                    // writing data that is bigger than the buffer (and the buffer
+                    // isn't currently locked due to a sub-object needing the size backfilled)
+                    Flush(writer); // commit any existing data from the buffer
+                    // now just write directly to the underlying stream
+                    writer.dest.Write(data, offset, length);
+                    writer.position += length; // since we've flushed offset etc is 0, and remains
+                                        // zero since we're writing directly to the stream
+                    return;
+            }
+            throw CreateException(writer);
+        CopyFixedLength: // no point duplicating this lots of times, and don't really want another stackframe
+            DemandSpace(length, writer);
+            Helpers.BlockCopy(data, offset, writer.ioBuffer, writer.ioIndex, length);
+            IncrementedAndReset(length, writer);
+        }
+        private static void CopyRawFromStream(Stream source, ProtoWriter writer)
+        {
+            byte[] buffer = writer.ioBuffer;
+            int space = buffer.Length - writer.ioIndex, bytesRead = 1; // 1 here to spoof case where already full
+            
+            // try filling the buffer first   
+            while (space > 0 && (bytesRead = source.Read(buffer, writer.ioIndex, space)) > 0)
+            {
+                writer.ioIndex += bytesRead;
+                writer.position += bytesRead;
+                space -= bytesRead;                
+            }
+            if (bytesRead <= 0) return; // all done using just the buffer; stream exhausted
+
+            // at this point the stream still has data, but buffer is full; 
+            if (writer.flushLock == 0)
+            {
+                // flush the buffer and write to the underlying stream instead
+                Flush(writer);
+                while ((bytesRead = source.Read(buffer, 0, buffer.Length)) > 0)
+                {
+                    writer.dest.Write(buffer, 0, bytesRead);
+                    writer.position += bytesRead;
+                }
+            }
+            else
+            {
+                do
+                {
+                    // need more space; resize (double) as necessary,
+                    // requesting a reasonable minimum chunk each time
+                    // (128 is the minimum; there may actually be much
+                    // more space than this in the buffer)
+                    DemandSpace(128, writer);
+                    if((bytesRead = source.Read(writer.ioBuffer, writer.ioIndex,
+                        writer.ioBuffer.Length - writer.ioIndex)) <= 0) break;
+                    writer.position += bytesRead;
+                    writer.ioIndex += bytesRead;
+                } while (true);
+            }
+
+        }
+        private static void IncrementedAndReset(int length, ProtoWriter writer)
+        {
+            Helpers.DebugAssert(length >= 0);
+            writer.ioIndex += length;
+            writer.position += length;
+            writer.wireType = WireType.None;
+        }
+        int depth = 0;
+        const int RecursionCheckDepth = 25;
+        /// <summary>
+        /// Indicates the start of a nested record.
+        /// </summary>
+        /// <param name="instance">The instance to write.</param>
+        /// <param name="writer">The destination.</param>
+        /// <returns>A token representing the state of the stream; this token is given to EndSubItem.</returns>
+        public static SubItemToken StartSubItem(object instance, ProtoWriter writer)
+        {
+            return StartSubItem(instance, writer, false);
+        }
+
+        MutableList recursionStack;
+        private void CheckRecursionStackAndPush(object instance)
+        {
+            int hitLevel;
+            if (recursionStack == null) { recursionStack = new MutableList(); }
+            else if (instance != null && (hitLevel = recursionStack.IndexOfReference(instance)) >= 0)
+            {
+#if DEBUG
+                Helpers.DebugWriteLine("Stack:");
+                foreach(object obj in recursionStack)
+                {
+                    Helpers.DebugWriteLine(obj == null ? "<null>" : obj.ToString());
+                }
+                Helpers.DebugWriteLine(instance == null ? "<null>" : instance.ToString());
+#endif
+                throw new ProtoException("Possible recursion detected (offset: " + (recursionStack.Count - hitLevel).ToString() + " level(s)): " + instance.ToString());
+            }
+            recursionStack.Add(instance);
+        }
+        private void PopRecursionStack() { recursionStack.RemoveLast(); }
+
+        private static SubItemToken StartSubItem(object instance, ProtoWriter writer, bool allowFixed)
+        {
+            if (writer == null) throw new ArgumentNullException("writer");
+            if (++writer.depth > RecursionCheckDepth)
+            {
+                writer.CheckRecursionStackAndPush(instance);
+            }
+            if(writer.packedFieldNumber != 0) throw new InvalidOperationException("Cannot begin a sub-item while performing packed encoding");
+            switch (writer.wireType)
+            {
+                case WireType.StartGroup:
+                    writer.wireType = WireType.None;
+                    return new SubItemToken(-writer.fieldNumber);
+                case WireType.String:
+#if DEBUG
+                    if(writer.model != null && writer.model.ForwardsOnly)
+                    {
+                        throw new ProtoException("Should not be buffering data");
+                    }
+#endif
+                    writer.wireType = WireType.None;
+                    DemandSpace(32, writer); // make some space in anticipation...
+                    writer.flushLock++;
+                    writer.position++;
+                    return new SubItemToken(writer.ioIndex++); // leave 1 space (optimistic) for length
+                case WireType.Fixed32:
+                    {
+                        if (!allowFixed) throw CreateException(writer);
+                        DemandSpace(32, writer); // make some space in anticipation...
+                        writer.flushLock++;
+                        SubItemToken token = new SubItemToken(writer.ioIndex);
+                        ProtoWriter.IncrementedAndReset(4, writer); // leave 4 space (rigid) for length
+                        return token;
+                    }
+                default:
+                    throw CreateException(writer);
+            }
+        }
+
+        /// <summary>
+        /// Indicates the end of a nested record.
+        /// </summary>
+        /// <param name="token">The token obtained from StartubItem.</param>
+        /// <param name="writer">The destination.</param>
+        public static void EndSubItem(SubItemToken token, ProtoWriter writer)
+        {
+            EndSubItem(token, writer, PrefixStyle.Base128);
+        }
+        private static void EndSubItem(SubItemToken token, ProtoWriter writer, PrefixStyle style)
+        {
+            if (writer == null) throw new ArgumentNullException("writer");
+            if (writer.wireType != WireType.None) { throw CreateException(writer); }
+            int value = token.value;
+            if (writer.depth <= 0) throw CreateException(writer);
+            if (writer.depth-- > RecursionCheckDepth)
+            {
+                writer.PopRecursionStack();
+            }
+            writer.packedFieldNumber = 0; // ending the sub-item always wipes packed encoding
+            if (value < 0)
+            {   // group - very simple append
+                WriteHeaderCore(-value, WireType.EndGroup, writer);
+                writer.wireType = WireType.None;
+                return;
+            }
+
+            // so we're backfilling the length into an existing sequence
+            int len;
+            switch(style)
+            {
+                case PrefixStyle.Fixed32:
+                    len = (int)((writer.ioIndex - value) - 4);
+                    ProtoWriter.WriteInt32ToBuffer(len, writer.ioBuffer, value);
+                    break;
+                case PrefixStyle.Fixed32BigEndian:
+                    len = (int)((writer.ioIndex - value) - 4);
+                    byte[] buffer = writer.ioBuffer;
+                    ProtoWriter.WriteInt32ToBuffer(len, buffer, value);
+                    // and swap the byte order
+                    byte b = buffer[value];
+                    buffer[value] = buffer[value + 3];
+                    buffer[value + 3] = b;
+                    b = buffer[value + 1];
+                    buffer[value + 1] = buffer[value + 2];
+                    buffer[value + 2] = b;
+                    break;
+                case PrefixStyle.Base128:
+                    // string - complicated because we only reserved one byte;
+                    // if the prefix turns out to need more than this then
+                    // we need to shuffle the existing data
+                    len = (int)((writer.ioIndex - value) - 1);
+                    int offset = 0;
+                    uint tmp = (uint)len;
+                    while ((tmp >>= 7) != 0) offset++;
+                    if (offset == 0)
+                    {
+                        writer.ioBuffer[value] = (byte)(len & 0x7F);
+                    }
+                    else
+                    {
+                        DemandSpace(offset, writer);
+                        byte[] blob = writer.ioBuffer;
+                        Helpers.BlockCopy(blob, value + 1, blob, value + 1 + offset, len);
+                        tmp = (uint)len;
+                        do
+                        {
+                            blob[value++] = (byte)((tmp & 0x7F) | 0x80);
+                        } while ((tmp >>= 7) != 0);
+                        blob[value - 1] = (byte)(blob[value - 1] & ~0x80);
+                        writer.position += offset;
+                        writer.ioIndex += offset;
+                    }
+                    break;
+                default:
+                    throw new ArgumentOutOfRangeException("style");
+            }
+            // and this object is no longer a blockage - also flush if sensible
+            const int ADVISORY_FLUSH_SIZE = 1024;
+            if (--writer.flushLock == 0 && writer.ioIndex >= ADVISORY_FLUSH_SIZE)
+            {
+                ProtoWriter.Flush(writer);
+            }
+            
+        }
+
+        /// <summary>
+        /// Creates a new writer against a stream
+        /// </summary>
+        /// <param name="dest">The destination stream</param>
+        /// <param name="model">The model to use for serialization; this can be null, but this will impair the ability to serialize sub-objects</param>
+        /// <param name="context">Additional context about this serialization operation</param>
+        public ProtoWriter(Stream dest, TypeModel model, SerializationContext context)
+        {
+            if (dest == null) throw new ArgumentNullException("dest");
+            if (!dest.CanWrite) throw new ArgumentException("Cannot write to stream", "dest");
+            //if (model == null) throw new ArgumentNullException("model");
+            this.dest = dest;
+            this.ioBuffer = BufferPool.GetBuffer();
+            this.model = model;
+            this.wireType = WireType.None;
+            if (context == null) { context = SerializationContext.Default; }
+            else { context.Freeze(); }
+            this.context = context;
+            
+        }
+
+        private readonly SerializationContext context;
+        /// <summary>
+        /// Addition information about this serialization operation.
+        /// </summary>
+        public SerializationContext Context { get { return context; } }
+        void IDisposable.Dispose()
+        {
+            Dispose();
+        }
+        private void Dispose()
+        {   // importantly, this does **not** own the stream, and does not dispose it
+            if (dest != null)
+            {
+                Flush(this);
+                dest = null;
+            }
+            model = null;
+            BufferPool.ReleaseBufferToPool(ref ioBuffer);
+        }
+
+        private byte[] ioBuffer;
+        private int ioIndex;
+        // note that this is used by some of the unit tests and should not be removed
+        internal static int GetPosition(ProtoWriter writer) { return writer.position; }
+        private int position;
+        private static void DemandSpace(int required, ProtoWriter writer)
+        {
+            // check for enough space
+            if ((writer.ioBuffer.Length - writer.ioIndex) < required)
+            {
+                if (writer.flushLock == 0)
+                {
+                    Flush(writer); // try emptying the buffer
+                    if ((writer.ioBuffer.Length - writer.ioIndex) >= required) return;
+                }
+                // either can't empty the buffer, or that didn't help; need more space
+                BufferPool.ResizeAndFlushLeft(ref writer.ioBuffer, required + writer.ioIndex, 0, writer.ioIndex);
+            }
+        }
+        /// <summary>
+        /// Flushes data to the underlying stream, and releases any resources. The underlying stream is *not* disposed
+        /// by this operation.
+        /// </summary>
+        public void Close()
+        {
+            if (depth != 0 || flushLock != 0) throw new InvalidOperationException("Unable to close stream in an incomplete state");
+            Dispose();
+        }
+
+        internal void CheckDepthFlushlock()
+        {
+            if (depth != 0 || flushLock != 0) throw new InvalidOperationException("The writer is in an incomplete state");
+        }
+
+        /// <summary>
+        /// Get the TypeModel associated with this writer
+        /// </summary>
+        public TypeModel Model { get { return model; } }
+
+        /// <summary>
+        /// Writes any buffered data (if possible) to the underlying stream.
+        /// </summary>
+        /// <param name="writer">The writer to flush</param>
+        /// <remarks>It is not always possible to fully flush, since some sequences
+        /// may require values to be back-filled into the byte-stream.</remarks>
+        internal static void Flush(ProtoWriter writer)
+        {
+            if (writer.flushLock == 0 && writer.ioIndex != 0)
+            {
+                writer.dest.Write(writer.ioBuffer, 0, writer.ioIndex);
+                writer.ioIndex = 0;                
+            }
+        }
+
+        /// <summary>
+        /// Writes an unsigned 32-bit integer to the stream; supported wire-types: Variant, Fixed32, Fixed64
+        /// </summary>
+        private static void WriteUInt32Variant(uint value, ProtoWriter writer)
+        {
+            DemandSpace(5, writer);
+            int count = 0;
+            do {
+                writer.ioBuffer[writer.ioIndex++] = (byte)((value & 0x7F) | 0x80);
+                count++;
+            } while ((value >>= 7) != 0);
+            writer.ioBuffer[writer.ioIndex - 1] &= 0x7F;
+            writer.position += count;
+        }
+ 
+        static readonly UTF8Encoding encoding = new UTF8Encoding();
+
+        internal static uint Zig(int value)
+        {        
+            return (uint)((value << 1) ^ (value >> 31));
+        }
+        internal static ulong Zig(long value)
+        {
+            return (ulong)((value << 1) ^ (value >> 63));
+        }
+        private static void WriteUInt64Variant(ulong value, ProtoWriter writer)
+        {
+            DemandSpace(10, writer);
+            int count = 0;
+            do
+            {
+                writer.ioBuffer[writer.ioIndex++] = (byte)((value & 0x7F) | 0x80);
+                count++;
+            } while ((value >>= 7) != 0);
+            writer.ioBuffer[writer.ioIndex - 1] &= 0x7F;
+            writer.position += count;
+        }
+        /// <summary>
+        /// Writes a string to the stream; supported wire-types: String
+        /// </summary>
+        public static void WriteString(string value, ProtoWriter writer)
+        {
+            if (writer == null) throw new ArgumentNullException("writer");
+            if (writer.wireType != WireType.String) throw CreateException(writer);
+            if (value == null) throw new ArgumentNullException("value"); // written header; now what?
+            int len = value.Length;
+            if (len == 0)
+            {
+                WriteUInt32Variant(0, writer);
+                writer.wireType = WireType.None;
+                return; // just a header
+            }
+#if MF
+            byte[] bytes = encoding.GetBytes(value);
+            int actual = bytes.Length;
+            writer.WriteUInt32Variant((uint)actual);
+            writer.Ensure(actual);
+            Helpers.BlockCopy(bytes, 0, writer.ioBuffer, writer.ioIndex, actual);
+#else
+            int predicted = encoding.GetByteCount(value);
+            WriteUInt32Variant((uint)predicted, writer);
+            DemandSpace(predicted, writer);
+            int actual = encoding.GetBytes(value, 0, value.Length, writer.ioBuffer, writer.ioIndex);
+            Helpers.DebugAssert(predicted == actual);
+#endif
+            IncrementedAndReset(actual, writer);
+        }
+        /// <summary>
+        /// Writes an unsigned 64-bit integer to the stream; supported wire-types: Variant, Fixed32, Fixed64
+        /// </summary>
+        public static void WriteUInt64(ulong value, ProtoWriter writer)
+        {
+            if (writer == null) throw new ArgumentNullException("writer");
+            switch (writer.wireType)
+            {
+                case WireType.Fixed64:
+                    ProtoWriter.WriteInt64((long)value, writer);
+                    return;
+                case WireType.Variant:
+                    WriteUInt64Variant(value, writer);
+                    writer.wireType = WireType.None;
+                    return;
+                case WireType.Fixed32:
+                    checked { ProtoWriter.WriteUInt32((uint)value, writer); }
+                    return;
+                default:
+                    throw CreateException(writer);
+            }
+        }
+
+        /// <summary>
+        /// Writes a signed 64-bit integer to the stream; supported wire-types: Variant, Fixed32, Fixed64, SignedVariant
+        /// </summary>
+        public static void WriteInt64(long value, ProtoWriter writer)
+        {
+            byte[] buffer;
+            int index;
+            if (writer == null) throw new ArgumentNullException("writer");
+            switch (writer.wireType)
+            {
+                case WireType.Fixed64:
+                    DemandSpace(8, writer);
+                    buffer = writer.ioBuffer;
+                    index = writer.ioIndex;
+                    buffer[index] = (byte)value;
+                    buffer[index + 1] = (byte)(value >> 8);
+                    buffer[index + 2] = (byte)(value >> 16);
+                    buffer[index + 3] = (byte)(value >> 24);
+                    buffer[index + 4] = (byte)(value >> 32);
+                    buffer[index + 5] = (byte)(value >> 40);
+                    buffer[index + 6] = (byte)(value >> 48);
+                    buffer[index + 7] = (byte)(value >> 56);
+                    IncrementedAndReset(8, writer);
+                    return;
+                case WireType.SignedVariant:
+                    WriteUInt64Variant(Zig(value), writer);
+                    writer.wireType = WireType.None;
+                    return;
+                case WireType.Variant:
+                    if (value >= 0)
+                    {
+                        WriteUInt64Variant((ulong)value, writer);
+                        writer.wireType = WireType.None;
+                    }
+                    else
+                    {
+                        DemandSpace(10, writer);
+                        buffer = writer.ioBuffer;
+                        index = writer.ioIndex;
+                        buffer[index] = (byte)(value | 0x80);
+                        buffer[index + 1] = (byte)((int)(value >> 7) | 0x80);
+                        buffer[index + 2] = (byte)((int)(value >> 14) | 0x80);
+                        buffer[index + 3] = (byte)((int)(value >> 21) | 0x80);
+                        buffer[index + 4] = (byte)((int)(value >> 28) | 0x80);
+                        buffer[index + 5] = (byte)((int)(value >> 35) | 0x80);
+                        buffer[index + 6] = (byte)((int)(value >> 42) | 0x80);
+                        buffer[index + 7] = (byte)((int)(value >> 49) | 0x80);
+                        buffer[index + 8] = (byte)((int)(value >> 56) | 0x80);
+                        buffer[index + 9] = 0x01; // sign bit
+                        IncrementedAndReset(10, writer);
+                    }
+                    return;
+                case WireType.Fixed32:
+                    checked { WriteInt32((int)value, writer); }
+                    return;
+                default:
+                    throw CreateException(writer);
+            }
+        }
+
+        /// <summary>
+        /// Writes an unsigned 16-bit integer to the stream; supported wire-types: Variant, Fixed32, Fixed64
+        /// </summary>
+        public static void WriteUInt32(uint value, ProtoWriter writer)
+        {
+            if (writer == null) throw new ArgumentNullException("writer");
+            switch (writer.wireType)
+            {
+                case WireType.Fixed32:
+                    ProtoWriter.WriteInt32((int)value, writer);
+                    return;
+                case WireType.Fixed64:
+                    ProtoWriter.WriteInt64((int)value, writer);
+                    return;
+                case WireType.Variant:
+                    WriteUInt32Variant(value, writer);
+                    writer.wireType = WireType.None;
+                    return;
+                default:
+                    throw CreateException(writer);
+            }
+        }
+
+
+        /// <summary>
+        /// Writes a signed 16-bit integer to the stream; supported wire-types: Variant, Fixed32, Fixed64, SignedVariant
+        /// </summary>
+        public static void WriteInt16(short value, ProtoWriter writer)
+        {
+            ProtoWriter.WriteInt32(value, writer);
+        }
+        /// <summary>
+        /// Writes an unsigned 16-bit integer to the stream; supported wire-types: Variant, Fixed32, Fixed64
+        /// </summary>
+        public static void WriteUInt16(ushort value, ProtoWriter writer)
+        {
+            ProtoWriter.WriteUInt32(value, writer);
+        }
+        /// <summary>
+        /// Writes an unsigned 8-bit integer to the stream; supported wire-types: Variant, Fixed32, Fixed64
+        /// </summary>
+        public static void WriteByte(byte value, ProtoWriter writer)
+        {
+            ProtoWriter.WriteUInt32(value, writer);
+        }
+        /// <summary>
+        /// Writes a signed 8-bit integer to the stream; supported wire-types: Variant, Fixed32, Fixed64, SignedVariant
+        /// </summary>
+        public static void WriteSByte(sbyte value, ProtoWriter writer)
+        {
+            ProtoWriter.WriteInt32(value, writer);
+        }
+        private static void WriteInt32ToBuffer(int value, byte[] buffer, int index)
+        {
+            buffer[index] = (byte)value;
+            buffer[index + 1] = (byte)(value >> 8);
+            buffer[index + 2] = (byte)(value >> 16);
+            buffer[index + 3] = (byte)(value >> 24);
+        }
+
+        /// <summary>
+        /// Writes a signed 32-bit integer to the stream; supported wire-types: Variant, Fixed32, Fixed64, SignedVariant
+        /// </summary>
+        public static void WriteInt32(int value, ProtoWriter writer)
+        {
+            byte[] buffer;
+            int index;
+            if (writer == null) throw new ArgumentNullException("writer");
+            switch (writer.wireType)
+            {
+                case WireType.Fixed32:
+                    DemandSpace(4, writer);
+                    WriteInt32ToBuffer(value, writer.ioBuffer, writer.ioIndex);                    
+                    IncrementedAndReset(4, writer);
+                    return;
+                case WireType.Fixed64:
+                    DemandSpace(8, writer);
+                    buffer = writer.ioBuffer;
+                    index = writer.ioIndex;
+                    buffer[index] = (byte)value;
+                    buffer[index + 1] = (byte)(value >> 8);
+                    buffer[index + 2] = (byte)(value >> 16);
+                    buffer[index + 3] = (byte)(value >> 24);
+                    buffer[index + 4] = buffer[index + 5] =
+                        buffer[index + 6] = buffer[index + 7] = 0;
+                    IncrementedAndReset(8, writer);
+                    return;
+                case WireType.SignedVariant:
+                    WriteUInt32Variant(Zig(value), writer);
+                    writer.wireType = WireType.None;
+                    return;
+                case WireType.Variant:
+                    if (value >= 0)
+                    {
+                        WriteUInt32Variant((uint)value, writer);
+                        writer.wireType = WireType.None;
+                    }
+                    else
+                    {
+                        DemandSpace(10, writer);
+                        buffer = writer.ioBuffer;
+                        index = writer.ioIndex;
+                        buffer[index] = (byte)(value | 0x80);
+                        buffer[index + 1] = (byte)((value >> 7) | 0x80);
+                        buffer[index + 2] = (byte)((value >> 14) | 0x80);
+                        buffer[index + 3] = (byte)((value >> 21) | 0x80);
+                        buffer[index + 4] = (byte)((value >> 28) | 0x80);
+                        buffer[index + 5] = buffer[index + 6] =
+                            buffer[index + 7] = buffer[index + 8] = (byte)0xFF;
+                        buffer[index + 9] = (byte)0x01;
+                        IncrementedAndReset(10, writer);
+                    }
+                    return;
+                default:
+                    throw CreateException(writer);
+            }
+            
+        }
+        /// <summary>
+        /// Writes a double-precision number to the stream; supported wire-types: Fixed32, Fixed64
+        /// </summary>
+        public
+#if !FEAT_SAFE
+            unsafe
+#endif
+
+                static void WriteDouble(double value, ProtoWriter writer)
+        {
+            if (writer == null) throw new ArgumentNullException("writer");
+            switch (writer.wireType)
+            {
+                case WireType.Fixed32:
+                    float f = (float)value;
+                    if (Helpers.IsInfinity(f)
+                        && !Helpers.IsInfinity(value))
+                    {
+                        throw new OverflowException();
+                    }
+                    ProtoWriter.WriteSingle(f, writer);
+                    return;
+                case WireType.Fixed64:
+#if FEAT_SAFE
+                    ProtoWriter.WriteInt64(BitConverter.ToInt64(BitConverter.GetBytes(value), 0), writer);
+#else
+                    ProtoWriter.WriteInt64(*(long*)&value, writer);
+#endif
+                    return;
+                default:
+                    throw CreateException(writer);
+            }
+        }
+        /// <summary>
+        /// Writes a single-precision number to the stream; supported wire-types: Fixed32, Fixed64
+        /// </summary>
+        public 
+#if !FEAT_SAFE
+            unsafe
+#endif
+            static void WriteSingle(float value, ProtoWriter writer)
+        {
+            if (writer == null) throw new ArgumentNullException("writer");
+            switch (writer.wireType)
+            {
+                case WireType.Fixed32:
+#if FEAT_SAFE
+                    ProtoWriter.WriteInt32(BitConverter.ToInt32(BitConverter.GetBytes(value), 0), writer);
+#else
+                    ProtoWriter.WriteInt32(*(int*)&value, writer);
+#endif
+                    return;
+                case WireType.Fixed64:
+                    ProtoWriter.WriteDouble((double)value, writer);
+                    return;
+                default:
+                    throw CreateException(writer);
+            }
+        }
+        /// <summary>
+        /// Throws an exception indicating that the given enum cannot be mapped to a serialized value.
+        /// </summary>
+        public static void ThrowEnumException(ProtoWriter writer, object enumValue)
+        {
+            if (writer == null) throw new ArgumentNullException("writer");
+            string rhs = enumValue == null ? "<null>" : (enumValue.GetType().FullName + "." + enumValue.ToString());
+            throw new ProtoException("No wire-value is mapped to the enum " + rhs + " at position " + writer.position.ToString());
+        }
+        // general purpose serialization exception message
+        internal static Exception CreateException(ProtoWriter writer)
+        {
+            if (writer == null) throw new ArgumentNullException("writer");
+            return new ProtoException("Invalid serialization operation with wire-type " + writer.wireType.ToString() + " at position " + writer.position.ToString());
+        }
+
+        /// <summary>
+        /// Writes a boolean to the stream; supported wire-types: Variant, Fixed32, Fixed64
+        /// </summary>
+        public static void WriteBoolean(bool value, ProtoWriter writer)
+        {
+            ProtoWriter.WriteUInt32(value ? (uint)1 : (uint)0, writer);
+        }
+
+        /// <summary>
+        /// Copies any extension data stored for the instance to the underlying stream
+        /// </summary>
+        public static void AppendExtensionData(IExtensible instance, ProtoWriter writer)
+        {
+            if (instance == null) throw new ArgumentNullException("instance");
+            if (writer == null) throw new ArgumentNullException("writer");
+            // we expect the writer to be raw here; the extension data will have the
+            // header detail, so we'll copy it implicitly
+            if(writer.wireType != WireType.None) throw CreateException(writer);
+
+            IExtension extn = instance.GetExtensionObject(false);
+            if (extn != null)
+            {
+                // unusually we *don't* want "using" here; the "finally" does that, with
+                // the extension object being responsible for disposal etc
+                Stream source = extn.BeginQuery();
+                try
+                {
+                    CopyRawFromStream(source, writer);
+                }
+                finally { extn.EndQuery(source); }
+            }
+        }
+
+
+        private int packedFieldNumber;
+        /// <summary>
+        /// Used for packed encoding; indicates that the next field should be skipped rather than
+        /// a field header written. Note that the field number must match, else an exception is thrown
+        /// when the attempt is made to write the (incorrect) field. The wire-type is taken from the
+        /// subsequent call to WriteFieldHeader. Only primitive types can be packed.
+        /// </summary>
+        public static void SetPackedField(int fieldNumber, ProtoWriter writer)
+        {
+            if (fieldNumber <= 0) throw new ArgumentOutOfRangeException("fieldNumber");
+            if (writer == null) throw new ArgumentNullException("writer");
+            writer.packedFieldNumber = fieldNumber;
+        }
+
+        internal string SerializeType(System.Type type)
+        {
+            return TypeModel.SerializeType(model, type);
+        }
+        /// <summary>
+        /// Specifies a known root object to use during reference-tracked serialization
+        /// </summary>
+        public void SetRootObject(object value)
+        {
+            NetCache.SetKeyedObject(NetObjectCache.Root, value);
+        }
+
+        /// <summary>
+        /// Writes a Type to the stream, using the model's DynamicTypeFormatting if appropriate; supported wire-types: String
+        /// </summary>
+        public static void WriteType(System.Type value, ProtoWriter writer)
+        {
+            if (writer == null) throw new ArgumentNullException("writer");
+            WriteString(writer.SerializeType(value), writer);
+        }
+    }
+}

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/ProtoWriter.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: ac8db25812bddf24b902467ec974bfab
+timeCreated: 1515899114
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 73 - 0
Unity/Assets/Plugins/protobuf-net/SerializationContext.cs

@@ -0,0 +1,73 @@
+using System;
+
+namespace ProtoBuf
+{
+    /// <summary>
+    /// Additional information about a serialization operation
+    /// </summary>
+    public sealed class SerializationContext
+    {
+        private bool frozen;
+        internal void Freeze() { frozen = true;}
+        private void ThrowIfFrozen() { if (frozen) throw new InvalidOperationException("The serialization-context cannot be changed once it is in use"); }
+        private object context;
+        /// <summary>
+        /// Gets or sets a user-defined object containing additional information about this serialization/deserialization operation.
+        /// </summary>
+        public object Context
+        {
+            get { return context; }
+            set { if (context != value) { ThrowIfFrozen(); context = value; } }
+        }
+
+        private static readonly SerializationContext @default;
+        static SerializationContext()
+        {
+            @default = new SerializationContext();
+            @default.Freeze();
+        }
+        /// <summary>
+        /// A default SerializationContext, with minimal information.
+        /// </summary>
+        internal static SerializationContext Default { get {return @default;}}
+#if PLAT_BINARYFORMATTER || (SILVERLIGHT && NET_4_0)
+
+#if !(WINRT || PHONE7 || PHONE8)
+        private System.Runtime.Serialization.StreamingContextStates state = System.Runtime.Serialization.StreamingContextStates.Persistence;
+        /// <summary>
+        /// Gets or sets the source or destination of the transmitted data.
+        /// </summary>
+        public System.Runtime.Serialization.StreamingContextStates State
+        {
+            get { return state; }
+            set { if (state != value) { ThrowIfFrozen(); state = value; } }
+        }
+#endif
+        /// <summary>
+        /// Convert a SerializationContext to a StreamingContext
+        /// </summary>
+        public static implicit operator System.Runtime.Serialization.StreamingContext(SerializationContext ctx)
+        {
+#if WINRT || PHONE7 || PHONE8
+            return new System.Runtime.Serialization.StreamingContext();
+#else
+            if (ctx == null) return new System.Runtime.Serialization.StreamingContext(System.Runtime.Serialization.StreamingContextStates.Persistence);
+            return new System.Runtime.Serialization.StreamingContext(ctx.state, ctx.context);
+#endif
+        }
+        /// <summary>
+        /// Convert a StreamingContext to a SerializationContext
+        /// </summary>
+        public static implicit operator SerializationContext (System.Runtime.Serialization.StreamingContext ctx)
+        {
+            SerializationContext result = new SerializationContext();
+#if !(WINRT || PHONE7 || PHONE8)
+            result.Context = ctx.Context;
+            result.State = ctx.State;
+#endif
+            return result;
+        }
+#endif
+    }
+
+}

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/SerializationContext.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 109710ee6086ef04b8f358cb7ffe53c5
+timeCreated: 1515899112
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 530 - 0
Unity/Assets/Plugins/protobuf-net/Serializer.cs

@@ -0,0 +1,530 @@
+
+using ProtoBuf.Meta;
+using System;
+using System.IO;
+#if !NO_GENERICS
+using System.Collections.Generic;
+#endif
+
+#if FEAT_IKVM
+using Type = IKVM.Reflection.Type;
+using IKVM.Reflection;
+#else
+using System.Reflection;
+#endif
+
+namespace ProtoBuf
+{
+    /// <summary>
+    /// Provides protocol-buffer serialization capability for concrete, attributed types. This
+    /// is a *default* model, but custom serializer models are also supported.
+    /// </summary>
+    /// <remarks>
+    /// Protocol-buffer serialization is a compact binary format, designed to take
+    /// advantage of sparse data and knowledge of specific data types; it is also
+    /// extensible, allowing a type to be deserialized / merged even if some data is
+    /// not recognised.
+    /// </remarks>
+    public 
+#if FX11
+    sealed
+#else
+    static
+#endif
+        class Serializer
+    {
+#if FX11
+        private Serializer() { } // not a static class for C# 1.2 reasons
+#endif
+#if !NO_RUNTIME && !NO_GENERICS
+        /// <summary>
+        /// Suggest a .proto definition for the given type
+        /// </summary>
+        /// <typeparam name="T">The type to generate a .proto definition for</typeparam>
+        /// <returns>The .proto definition as a string</returns>
+        public static string GetProto<T>()
+        {
+            return RuntimeTypeModel.Default.GetSchema(RuntimeTypeModel.Default.MapType(typeof(T)));
+        }
+        /// <summary>
+        /// Create a deep clone of the supplied instance; any sub-items are also cloned.
+        /// </summary>
+        public static T DeepClone<T>(T instance)
+        {
+            return instance == null ? instance : (T)RuntimeTypeModel.Default.DeepClone(instance);
+        }
+        /// <summary>
+        /// Applies a protocol-buffer stream to an existing instance.
+        /// </summary>
+        /// <typeparam name="T">The type being merged.</typeparam>
+        /// <param name="instance">The existing instance to be modified (can be null).</param>
+        /// <param name="source">The binary stream to apply to the instance (cannot be null).</param>
+        /// <returns>The updated instance; this may be different to the instance argument if
+        /// either the original instance was null, or the stream defines a known sub-type of the
+        /// original instance.</returns>
+        public static T Merge<T>(Stream source, T instance)
+        {
+            return (T)RuntimeTypeModel.Default.Deserialize(source, instance, typeof(T));
+        }
+        /// <summary>
+        /// Creates a new instance from a protocol-buffer stream
+        /// </summary>
+        /// <typeparam name="T">The type to be created.</typeparam>
+        /// <param name="source">The binary stream to apply to the new instance (cannot be null).</param>
+        /// <returns>A new, initialized instance.</returns>
+        public static T Deserialize<T>(Stream source)
+        {
+            return (T) RuntimeTypeModel.Default.Deserialize(source, null, typeof(T));
+        }
+        /// <summary>
+        /// Writes a protocol-buffer representation of the given instance to the supplied stream.
+        /// </summary>
+        /// <param name="instance">The existing instance to be serialized (cannot be null).</param>
+        /// <param name="destination">The destination stream to write to.</param>
+        public static void Serialize<T>(Stream destination, T instance)
+        {
+            if(instance != null) {
+                RuntimeTypeModel.Default.Serialize(destination, instance);
+            }
+        }
+        /// <summary>
+        /// Serializes a given instance and deserializes it as a different type;
+        /// this can be used to translate between wire-compatible objects (where
+        /// two .NET types represent the same data), or to promote/demote a type
+        /// through an inheritance hierarchy.
+        /// </summary>
+        /// <remarks>No assumption of compatibility is made between the types.</remarks>
+        /// <typeparam name="TFrom">The type of the object being copied.</typeparam>
+        /// <typeparam name="TTo">The type of the new object to be created.</typeparam>
+        /// <param name="instance">The existing instance to use as a template.</param>
+        /// <returns>A new instane of type TNewType, with the data from TOldType.</returns>
+        public static TTo ChangeType<TFrom,TTo>(TFrom instance)
+        {
+            using (MemoryStream ms = new MemoryStream())
+            {
+                Serialize<TFrom>(ms, instance);
+                ms.Position = 0;
+                return Deserialize<TTo>(ms);
+            }
+        }
+#if PLAT_BINARYFORMATTER && !(WINRT || PHONE8)
+        /// <summary>
+        /// Writes a protocol-buffer representation of the given instance to the supplied SerializationInfo.
+        /// </summary>
+        /// <typeparam name="T">The type being serialized.</typeparam>
+        /// <param name="instance">The existing instance to be serialized (cannot be null).</param>
+        /// <param name="info">The destination SerializationInfo to write to.</param>
+        public static void Serialize<T>(System.Runtime.Serialization.SerializationInfo info, T instance) where T : class, System.Runtime.Serialization.ISerializable
+        {
+            Serialize<T>(info, new System.Runtime.Serialization.StreamingContext(System.Runtime.Serialization.StreamingContextStates.Persistence), instance);
+        }
+        /// <summary>
+        /// Writes a protocol-buffer representation of the given instance to the supplied SerializationInfo.
+        /// </summary>
+        /// <typeparam name="T">The type being serialized.</typeparam>
+        /// <param name="instance">The existing instance to be serialized (cannot be null).</param>
+        /// <param name="info">The destination SerializationInfo to write to.</param>
+        /// <param name="context">Additional information about this serialization operation.</param>
+        public static void Serialize<T>(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context, T instance) where T : class, System.Runtime.Serialization.ISerializable
+        {
+            // note: also tried byte[]... it doesn't perform hugely well with either (compared to regular serialization)
+            if (info == null) throw new ArgumentNullException("info");
+            if (instance == null) throw new ArgumentNullException("instance");
+            if (instance.GetType() != typeof(T)) throw new ArgumentException("Incorrect type", "instance");
+            using (MemoryStream ms = new MemoryStream())
+            {
+                RuntimeTypeModel.Default.Serialize(ms, instance, context);
+                info.AddValue(ProtoBinaryField, ms.ToArray());
+            }
+        }
+#endif
+#if PLAT_XMLSERIALIZER
+        /// <summary>
+        /// Writes a protocol-buffer representation of the given instance to the supplied XmlWriter.
+        /// </summary>
+        /// <typeparam name="T">The type being serialized.</typeparam>
+        /// <param name="instance">The existing instance to be serialized (cannot be null).</param>
+        /// <param name="writer">The destination XmlWriter to write to.</param>
+        public static void Serialize<T>(System.Xml.XmlWriter writer, T instance) where T : System.Xml.Serialization.IXmlSerializable
+        {
+            if (writer == null) throw new ArgumentNullException("writer");
+            if (instance == null) throw new ArgumentNullException("instance");
+
+            using (MemoryStream ms = new MemoryStream())
+            {
+                Serializer.Serialize(ms, instance);
+                writer.WriteBase64(ms.GetBuffer(), 0, (int)ms.Length);
+            }
+        }
+        /// <summary>
+        /// Applies a protocol-buffer from an XmlReader to an existing instance.
+        /// </summary>
+        /// <typeparam name="T">The type being merged.</typeparam>
+        /// <param name="instance">The existing instance to be modified (cannot be null).</param>
+        /// <param name="reader">The XmlReader containing the data to apply to the instance (cannot be null).</param>
+        public static void Merge<T>(System.Xml.XmlReader reader, T instance) where T : System.Xml.Serialization.IXmlSerializable
+        {
+            if (reader == null) throw new ArgumentNullException("reader");
+            if (instance == null) throw new ArgumentNullException("instance");
+
+            const int LEN = 4096;
+            byte[] buffer = new byte[LEN];
+            int read;
+            using (MemoryStream ms = new MemoryStream())
+            {
+                int depth = reader.Depth;
+                while(reader.Read() && reader.Depth > depth)
+                {
+                    if (reader.NodeType == System.Xml.XmlNodeType.Text)
+                    {
+                        while ((read = reader.ReadContentAsBase64(buffer, 0, LEN)) > 0)
+                        {
+                            ms.Write(buffer, 0, read);
+                        }
+                        if (reader.Depth <= depth) break;
+                    }
+                }
+                ms.Position = 0;
+                Serializer.Merge(ms, instance);
+            }
+        }
+#endif
+
+        private const string ProtoBinaryField = "proto";
+#if PLAT_BINARYFORMATTER && !NO_GENERICS && !(WINRT || PHONE8)
+        /// <summary>
+        /// Applies a protocol-buffer from a SerializationInfo to an existing instance.
+        /// </summary>
+        /// <typeparam name="T">The type being merged.</typeparam>
+        /// <param name="instance">The existing instance to be modified (cannot be null).</param>
+        /// <param name="info">The SerializationInfo containing the data to apply to the instance (cannot be null).</param>
+        public static void Merge<T>(System.Runtime.Serialization.SerializationInfo info, T instance) where T : class, System.Runtime.Serialization.ISerializable
+        {
+            Merge<T>(info, new System.Runtime.Serialization.StreamingContext(System.Runtime.Serialization.StreamingContextStates.Persistence), instance);
+        }
+        /// <summary>
+        /// Applies a protocol-buffer from a SerializationInfo to an existing instance.
+        /// </summary>
+        /// <typeparam name="T">The type being merged.</typeparam>
+        /// <param name="instance">The existing instance to be modified (cannot be null).</param>
+        /// <param name="info">The SerializationInfo containing the data to apply to the instance (cannot be null).</param>
+        /// <param name="context">Additional information about this serialization operation.</param>
+        public static void Merge<T>(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context, T instance) where T : class, System.Runtime.Serialization.ISerializable
+        {
+            // note: also tried byte[]... it doesn't perform hugely well with either (compared to regular serialization)
+            if (info == null) throw new ArgumentNullException("info");
+            if (instance == null) throw new ArgumentNullException("instance");
+            if (instance.GetType() != typeof(T)) throw new ArgumentException("Incorrect type", "instance");
+
+            byte[] buffer = (byte[])info.GetValue(ProtoBinaryField, typeof(byte[]));
+            using (MemoryStream ms = new MemoryStream(buffer))
+            {
+                T result = (T)RuntimeTypeModel.Default.Deserialize(ms, instance, typeof(T), context);
+                if (!ReferenceEquals(result, instance))
+                {
+                    throw new ProtoException("Deserialization changed the instance; cannot succeed.");
+                }
+            }
+        }
+#endif
+
+#if !NO_GENERICS
+        /// <summary>
+        /// Precompiles the serializer for a given type.
+        /// </summary>
+        public static void PrepareSerializer<T>()
+        { 
+#if FEAT_COMPILER
+            RuntimeTypeModel model = RuntimeTypeModel.Default;
+            model[model.MapType(typeof(T))].CompileInPlace();
+#endif
+        }
+
+#if PLAT_BINARYFORMATTER && !(WINRT || PHONE8)
+        /// <summary>
+        /// Creates a new IFormatter that uses protocol-buffer [de]serialization.
+        /// </summary>
+        /// <typeparam name="T">The type of object to be [de]deserialized by the formatter.</typeparam>
+        /// <returns>A new IFormatter to be used during [de]serialization.</returns>
+        public static System.Runtime.Serialization.IFormatter CreateFormatter<T>()
+        {
+#if FEAT_IKVM
+            throw new NotSupportedException();
+#else
+            return RuntimeTypeModel.Default.CreateFormatter(typeof(T));
+#endif
+        }
+#endif
+        /// <summary>
+        /// Reads a sequence of consecutive length-prefixed items from a stream, using
+        /// either base-128 or fixed-length prefixes. Base-128 prefixes with a tag
+        /// are directly comparable to serializing multiple items in succession
+        /// (use the <see cref="ListItemTag"/> tag to emulate the implicit behavior
+        /// when serializing a list/array). When a tag is
+        /// specified, any records with different tags are silently omitted. The
+        /// tag is ignored. The tag is ignores for fixed-length prefixes.
+        /// </summary>
+        /// <typeparam name="T">The type of object to deserialize.</typeparam>
+        /// <param name="source">The binary stream containing the serialized records.</param>
+        /// <param name="style">The prefix style used in the data.</param>
+        /// <param name="fieldNumber">The tag of records to return (if non-positive, then no tag is
+        /// expected and all records are returned).</param>
+        /// <returns>The sequence of deserialized objects.</returns>
+        public static IEnumerable<T> DeserializeItems<T>(Stream source, PrefixStyle style, int fieldNumber)
+        {
+            return RuntimeTypeModel.Default.DeserializeItems<T>(source, style, fieldNumber);
+        }
+
+        /// <summary>
+        /// Creates a new instance from a protocol-buffer stream that has a length-prefix
+        /// on data (to assist with network IO).
+        /// </summary>
+        /// <typeparam name="T">The type to be created.</typeparam>
+        /// <param name="source">The binary stream to apply to the new instance (cannot be null).</param>
+        /// <param name="style">How to encode the length prefix.</param>
+        /// <returns>A new, initialized instance.</returns>
+        public static T DeserializeWithLengthPrefix<T>(Stream source, PrefixStyle style)
+        {
+            return DeserializeWithLengthPrefix<T>(source, style, 0);
+        }
+
+        /// <summary>
+        /// Creates a new instance from a protocol-buffer stream that has a length-prefix
+        /// on data (to assist with network IO).
+        /// </summary>
+        /// <typeparam name="T">The type to be created.</typeparam>
+        /// <param name="source">The binary stream to apply to the new instance (cannot be null).</param>
+        /// <param name="style">How to encode the length prefix.</param>
+        /// <param name="fieldNumber">The expected tag of the item (only used with base-128 prefix style).</param>
+        /// <returns>A new, initialized instance.</returns>
+        public static T DeserializeWithLengthPrefix<T>(Stream source, PrefixStyle style, int fieldNumber)
+        {
+            RuntimeTypeModel model = RuntimeTypeModel.Default;
+            return (T)model.DeserializeWithLengthPrefix(source, null, model.MapType(typeof(T)), style, fieldNumber);
+        }
+
+        /// <summary>
+        /// Applies a protocol-buffer stream to an existing instance, using length-prefixed
+        /// data - useful with network IO.
+        /// </summary>
+        /// <typeparam name="T">The type being merged.</typeparam>
+        /// <param name="instance">The existing instance to be modified (can be null).</param>
+        /// <param name="source">The binary stream to apply to the instance (cannot be null).</param>
+        /// <param name="style">How to encode the length prefix.</param>
+        /// <returns>The updated instance; this may be different to the instance argument if
+        /// either the original instance was null, or the stream defines a known sub-type of the
+        /// original instance.</returns>
+        public static T MergeWithLengthPrefix<T>(Stream source, T instance, PrefixStyle style)
+        {
+            RuntimeTypeModel model = RuntimeTypeModel.Default;
+            return (T)model.DeserializeWithLengthPrefix(source, instance, model.MapType(typeof(T)), style, 0);
+        }
+
+        /// <summary>
+        /// Writes a protocol-buffer representation of the given instance to the supplied stream,
+        /// with a length-prefix. This is useful for socket programming,
+        /// as DeserializeWithLengthPrefix/MergeWithLengthPrefix can be used to read the single object back
+        /// from an ongoing stream.
+        /// </summary>
+        /// <typeparam name="T">The type being serialized.</typeparam>
+        /// <param name="instance">The existing instance to be serialized (cannot be null).</param>
+        /// <param name="style">How to encode the length prefix.</param>
+        /// <param name="destination">The destination stream to write to.</param>
+        public static void SerializeWithLengthPrefix<T>(Stream destination, T instance, PrefixStyle style)
+        {
+            SerializeWithLengthPrefix<T>(destination, instance, style, 0);
+        }
+
+        /// <summary>
+        /// Writes a protocol-buffer representation of the given instance to the supplied stream,
+        /// with a length-prefix. This is useful for socket programming,
+        /// as DeserializeWithLengthPrefix/MergeWithLengthPrefix can be used to read the single object back
+        /// from an ongoing stream.
+        /// </summary>
+        /// <typeparam name="T">The type being serialized.</typeparam>
+        /// <param name="instance">The existing instance to be serialized (cannot be null).</param>
+        /// <param name="style">How to encode the length prefix.</param>
+        /// <param name="destination">The destination stream to write to.</param>
+        /// <param name="fieldNumber">The tag used as a prefix to each record (only used with base-128 style prefixes).</param>
+        public static void SerializeWithLengthPrefix<T>(Stream destination, T instance, PrefixStyle style, int fieldNumber)
+        {
+            RuntimeTypeModel model = RuntimeTypeModel.Default;
+            model.SerializeWithLengthPrefix(destination, instance, model.MapType(typeof(T)), style, fieldNumber);
+        }
+#endif
+        /// <summary>Indicates the number of bytes expected for the next message.</summary>
+        /// <param name="source">The stream containing the data to investigate for a length.</param>
+        /// <param name="style">The algorithm used to encode the length.</param>
+        /// <param name="length">The length of the message, if it could be identified.</param>
+        /// <returns>True if a length could be obtained, false otherwise.</returns>
+        public static bool TryReadLengthPrefix(Stream source, PrefixStyle style, out int length)
+        {
+            int fieldNumber, bytesRead;
+            length = ProtoReader.ReadLengthPrefix(source, false, style, out fieldNumber, out bytesRead);
+            return bytesRead > 0;
+        }
+
+        /// <summary>Indicates the number of bytes expected for the next message.</summary>
+        /// <param name="buffer">The buffer containing the data to investigate for a length.</param>
+        /// <param name="index">The offset of the first byte to read from the buffer.</param>
+        /// <param name="count">The number of bytes to read from the buffer.</param>
+        /// <param name="style">The algorithm used to encode the length.</param>
+        /// <param name="length">The length of the message, if it could be identified.</param>
+        /// <returns>True if a length could be obtained, false otherwise.</returns>
+        public static bool TryReadLengthPrefix(byte[] buffer, int index, int count, PrefixStyle style, out int length)
+        {
+            using (Stream source = new MemoryStream(buffer, index, count))
+            {
+                return TryReadLengthPrefix(source, style, out length);
+            }
+        }
+#endif
+        /// <summary>
+        /// The field number that is used as a default when serializing/deserializing a list of objects.
+        /// The data is treated as repeated message with field number 1.
+        /// </summary>
+        public const int ListItemTag = 1;
+
+
+
+#if !NO_RUNTIME
+        /// <summary>
+        /// Provides non-generic access to the default serializer.
+        /// </summary>
+        public
+#if FX11
+    sealed
+#else
+    static
+#endif
+            class NonGeneric
+        {
+#if FX11
+            private NonGeneric() { } // not a static class for C# 1.2 reasons
+#endif
+            /// <summary>
+            /// Create a deep clone of the supplied instance; any sub-items are also cloned.
+            /// </summary>
+            public static object DeepClone(object instance)
+            {
+                return instance == null ? null : RuntimeTypeModel.Default.DeepClone(instance);
+            }
+
+            /// <summary>
+            /// Writes a protocol-buffer representation of the given instance to the supplied stream.
+            /// </summary>
+            /// <param name="instance">The existing instance to be serialized (cannot be null).</param>
+            /// <param name="dest">The destination stream to write to.</param>
+            public static void Serialize(Stream dest, object instance)
+            {
+                if (instance != null)
+                {
+                    RuntimeTypeModel.Default.Serialize(dest, instance);
+                }
+            }
+
+            /// <summary>
+            /// Creates a new instance from a protocol-buffer stream
+            /// </summary>
+            /// <param name="type">The type to be created.</param>
+            /// <param name="source">The binary stream to apply to the new instance (cannot be null).</param>
+            /// <returns>A new, initialized instance.</returns>
+            public static object Deserialize(System.Type type, Stream source)
+            {
+                return RuntimeTypeModel.Default.Deserialize(source, null, type);
+            }
+
+            /// <summary>Applies a protocol-buffer stream to an existing instance.</summary>
+            /// <param name="instance">The existing instance to be modified (cannot be null).</param>
+            /// <param name="source">The binary stream to apply to the instance (cannot be null).</param>
+            /// <returns>The updated instance</returns>
+            public static object Merge(Stream source, object instance)
+            {
+                if (instance == null) throw new ArgumentNullException("instance");
+                return RuntimeTypeModel.Default.Deserialize(source, instance, instance.GetType(), null);
+            }
+
+            /// <summary>
+            /// Writes a protocol-buffer representation of the given instance to the supplied stream,
+            /// with a length-prefix. This is useful for socket programming,
+            /// as DeserializeWithLengthPrefix/MergeWithLengthPrefix can be used to read the single object back
+            /// from an ongoing stream.
+            /// </summary>
+            /// <param name="instance">The existing instance to be serialized (cannot be null).</param>
+            /// <param name="style">How to encode the length prefix.</param>
+            /// <param name="destination">The destination stream to write to.</param>
+            /// <param name="fieldNumber">The tag used as a prefix to each record (only used with base-128 style prefixes).</param>
+            public static void SerializeWithLengthPrefix(Stream destination, object instance, PrefixStyle style, int fieldNumber)
+            {
+                if (instance == null) throw new ArgumentNullException("instance");
+                RuntimeTypeModel model = RuntimeTypeModel.Default;                
+                model.SerializeWithLengthPrefix(destination, instance, model.MapType(instance.GetType()), style, fieldNumber);
+            }
+            /// <summary>
+            /// Applies a protocol-buffer stream to an existing instance (or null), using length-prefixed
+            /// data - useful with network IO.
+            /// </summary>
+            /// <param name="value">The existing instance to be modified (can be null).</param>
+            /// <param name="source">The binary stream to apply to the instance (cannot be null).</param>
+            /// <param name="style">How to encode the length prefix.</param>
+            /// <param name="resolver">Used to resolve types on a per-field basis.</param>
+            /// <returns>The updated instance; this may be different to the instance argument if
+            /// either the original instance was null, or the stream defines a known sub-type of the
+            /// original instance.</returns>
+            public static bool TryDeserializeWithLengthPrefix(Stream source, PrefixStyle style, TypeResolver resolver, out object value)
+            {
+                value = RuntimeTypeModel.Default.DeserializeWithLengthPrefix(source, null, null, style, 0, resolver);
+                return value != null;
+            }
+            /// <summary>
+            /// Indicates whether the supplied type is explicitly modelled by the model
+            /// </summary>
+            public static bool CanSerialize(Type type)
+            {
+                return RuntimeTypeModel.Default.IsDefined(type);
+            }
+
+        }
+
+
+        /// <summary>
+        /// Global switches that change the behavior of protobuf-net
+        /// </summary>
+        public
+#if FX11
+    sealed
+#else
+    static
+#endif
+            class GlobalOptions
+        {
+#if FX11
+            private GlobalOptions() { } // not a static class for C# 1.2 reasons
+#endif
+            /// <summary>
+            /// <see cref="RuntimeTypeModel.InferTagFromNameDefault"/>
+            /// </summary>
+            [Obsolete("Please use RuntimeTypeModel.Default.InferTagFromNameDefault instead (or on a per-model basis)", false)]
+            public static bool InferTagFromName
+            {
+                get { return RuntimeTypeModel.Default.InferTagFromNameDefault; }
+                set { RuntimeTypeModel.Default.InferTagFromNameDefault = value; }
+            }
+        }
+#endif
+        /// <summary>
+        /// Maps a field-number to a type
+        /// </summary>
+        public delegate Type TypeResolver(int fieldNumber);
+
+        /// <summary>
+        /// Releases any internal buffers that have been reserved for efficiency; this does not affect any serialization
+        /// operations; simply: it can be used (optionally) to release the buffers for garbage collection (at the expense
+        /// of having to re-allocate a new buffer for the next operation, rather than re-use prior buffers).
+        /// </summary>
+        public static void FlushPool()
+        {
+            BufferPool.Flush();
+        }
+    }
+}

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/Serializer.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: cc69fe9313014d84393d85eec0f7df15
+timeCreated: 1515899114
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 3 - 3
Unity/Assets/Plugins/protobuf-net/Serializers.meta

@@ -1,8 +1,8 @@
 fileFormatVersion: 2
-guid: d601d2118bca0dd46bce3c210a21520b
+guid: c9a353e0468a96448b7e9f8d8af63ad0
 folderAsset: yes
-timeCreated: 1513686875
-licenseType: Free
+timeCreated: 1515899111
+licenseType: Pro
 DefaultImporter:
   userData: 
   assetBundleName: 

+ 271 - 0
Unity/Assets/Plugins/protobuf-net/Serializers/ArrayDecorator.cs

@@ -0,0 +1,271 @@
+#if !NO_RUNTIME
+using System;
+using System.Collections;
+using ProtoBuf.Meta;
+
+#if FEAT_IKVM
+using Type = IKVM.Reflection.Type;
+using IKVM.Reflection;
+#else
+using System.Reflection;
+#endif
+
+namespace ProtoBuf.Serializers
+{
+    sealed class ArrayDecorator : ProtoDecoratorBase
+    {
+
+        private readonly int fieldNumber;
+        private const byte
+                   OPTIONS_WritePacked = 1,
+                   OPTIONS_OverwriteList = 2,
+                   OPTIONS_SupportNull = 4;
+        private readonly byte options;
+        private readonly WireType packedWireType;
+        public ArrayDecorator(TypeModel model, IProtoSerializer tail, int fieldNumber, bool writePacked, WireType packedWireType, Type arrayType, bool overwriteList, bool supportNull)
+            : base(tail)
+        {
+            Helpers.DebugAssert(arrayType != null, "arrayType should be non-null");
+            Helpers.DebugAssert(arrayType.IsArray && arrayType.GetArrayRank() == 1, "should be single-dimension array; " + arrayType.FullName);
+            this.itemType = arrayType.GetElementType();
+#if NO_GENERICS
+            Type underlyingItemType = itemType;
+#else
+            Type underlyingItemType = supportNull ? itemType : (Helpers.GetUnderlyingType(itemType) ?? itemType);
+#endif
+
+            Helpers.DebugAssert(underlyingItemType == Tail.ExpectedType, "invalid tail");
+            Helpers.DebugAssert(Tail.ExpectedType != model.MapType(typeof(byte)), "Should have used BlobSerializer");
+            if ((writePacked || packedWireType != WireType.None) && fieldNumber <= 0) throw new ArgumentOutOfRangeException("fieldNumber");
+            if (!ListDecorator.CanPack(packedWireType))
+            {
+                if (writePacked) throw new InvalidOperationException("Only simple data-types can use packed encoding");
+                packedWireType = WireType.None;
+            }       
+            this.fieldNumber = fieldNumber;
+            this.packedWireType = packedWireType;
+            if (writePacked) options |= OPTIONS_WritePacked;
+            if (overwriteList) options |= OPTIONS_OverwriteList;
+            if (supportNull) options |= OPTIONS_SupportNull;
+            this.arrayType = arrayType;
+        }
+        readonly Type arrayType, itemType; // this is, for example, typeof(int[])
+        public override Type ExpectedType { get { return arrayType; } }
+        public override bool RequiresOldValue { get { return AppendToCollection; } }
+        public override bool ReturnsValue { get { return true; } }
+#if FEAT_COMPILER
+        protected override void EmitWrite(ProtoBuf.Compiler.CompilerContext ctx, ProtoBuf.Compiler.Local valueFrom)
+        {
+            // int i and T[] arr
+            using (Compiler.Local arr = ctx.GetLocalWithValue(arrayType, valueFrom))
+            using (Compiler.Local i = new ProtoBuf.Compiler.Local(ctx, ctx.MapType(typeof(int))))
+            {
+                bool writePacked = (options & OPTIONS_WritePacked) != 0;
+                using (Compiler.Local token = writePacked ? new Compiler.Local(ctx, ctx.MapType(typeof(SubItemToken))) : null)
+                {
+                    Type mappedWriter = ctx.MapType(typeof (ProtoWriter));
+                    if (writePacked)
+                    {
+                        ctx.LoadValue(fieldNumber);
+                        ctx.LoadValue((int)WireType.String);
+                        ctx.LoadReaderWriter();
+                        ctx.EmitCall(mappedWriter.GetMethod("WriteFieldHeader"));
+
+                        ctx.LoadValue(arr);
+                        ctx.LoadReaderWriter();
+                        ctx.EmitCall(mappedWriter.GetMethod("StartSubItem"));
+                        ctx.StoreValue(token);
+
+                        ctx.LoadValue(fieldNumber);
+                        ctx.LoadReaderWriter();
+                        ctx.EmitCall(mappedWriter.GetMethod("SetPackedField"));
+                    }
+                    EmitWriteArrayLoop(ctx, i, arr);
+
+                    if (writePacked)
+                    {
+                        ctx.LoadValue(token);
+                        ctx.LoadReaderWriter();
+                        ctx.EmitCall(mappedWriter.GetMethod("EndSubItem"));
+                    }
+                }
+            }
+        }
+
+        private void EmitWriteArrayLoop(Compiler.CompilerContext ctx, Compiler.Local i, Compiler.Local arr)
+        {
+            // i = 0
+            ctx.LoadValue(0);
+            ctx.StoreValue(i);
+
+            // range test is last (to minimise branches)
+            Compiler.CodeLabel loopTest = ctx.DefineLabel(), processItem = ctx.DefineLabel();
+            ctx.Branch(loopTest, false);
+            ctx.MarkLabel(processItem);
+
+            // {...}
+            ctx.LoadArrayValue(arr, i);
+            if (SupportNull)
+            {
+                Tail.EmitWrite(ctx, null);
+            }
+            else
+            {
+                ctx.WriteNullCheckedTail(itemType, Tail, null);
+            }
+
+            // i++
+            ctx.LoadValue(i);
+            ctx.LoadValue(1);
+            ctx.Add();
+            ctx.StoreValue(i);
+
+            // i < arr.Length
+            ctx.MarkLabel(loopTest);
+            ctx.LoadValue(i);
+            ctx.LoadLength(arr, false);
+            ctx.BranchIfLess(processItem, false);
+        }
+#endif
+        private bool AppendToCollection
+        {
+            get { return (options & OPTIONS_OverwriteList) == 0; }
+        }
+        private bool SupportNull { get { return (options & OPTIONS_SupportNull) != 0; } }
+
+#if !FEAT_IKVM
+        public override void Write(object value, ProtoWriter dest)
+        {
+            IList arr = (IList)value;
+            int len = arr.Count;
+            SubItemToken token;
+            bool writePacked = (options & OPTIONS_WritePacked) != 0;
+            if (writePacked)
+            {
+                ProtoWriter.WriteFieldHeader(fieldNumber, WireType.String, dest);
+                token = ProtoWriter.StartSubItem(value, dest);
+                ProtoWriter.SetPackedField(fieldNumber, dest);
+            }
+            else
+            {
+                token = new SubItemToken(); // default
+            }
+            bool checkForNull = !SupportNull;
+            for (int i = 0; i < len; i++)
+            {
+                object obj = arr[i];
+                if (checkForNull && obj == null) { throw new NullReferenceException(); }
+                Tail.Write(obj, dest);
+            }
+            if (writePacked)
+            {
+                ProtoWriter.EndSubItem(token, dest);
+            }            
+        }
+        public override object Read(object value, ProtoReader source)
+        {
+            int field = source.FieldNumber;
+            BasicList list = new BasicList();
+            if (packedWireType != WireType.None && source.WireType == WireType.String)
+            {
+                SubItemToken token = ProtoReader.StartSubItem(source);
+                while (ProtoReader.HasSubValue(packedWireType, source))
+                {
+                    list.Add(Tail.Read(null, source));
+                }
+                ProtoReader.EndSubItem(token, source);
+            }
+            else
+            { 
+                do
+                {
+                    list.Add(Tail.Read(null, source));
+                } while (source.TryReadFieldHeader(field));
+            }
+            int oldLen = AppendToCollection ? ((value == null ? 0 : ((Array)value).Length)) : 0;
+            Array result = Array.CreateInstance(itemType, oldLen + list.Count);
+            if (oldLen != 0) ((Array)value).CopyTo(result, 0);
+            list.CopyTo(result, oldLen);
+            return result;
+        }
+#endif
+
+#if FEAT_COMPILER
+        protected override void EmitRead(ProtoBuf.Compiler.CompilerContext ctx, ProtoBuf.Compiler.Local valueFrom)
+        {
+            Type listType;
+#if NO_GENERICS
+            listType = typeof(BasicList);
+#else
+            listType = ctx.MapType(typeof(System.Collections.Generic.List<>)).MakeGenericType(itemType);
+#endif
+            Type expected = ExpectedType;
+            using (Compiler.Local oldArr = AppendToCollection ? ctx.GetLocalWithValue(expected, valueFrom) : null)
+            using (Compiler.Local newArr = new Compiler.Local(ctx, expected))
+            using (Compiler.Local list = new Compiler.Local(ctx, listType))
+            {
+                ctx.EmitCtor(listType);
+                ctx.StoreValue(list);
+                ListDecorator.EmitReadList(ctx, list, Tail, listType.GetMethod("Add"), packedWireType, false);
+
+                // leave this "using" here, as it can share the "FieldNumber" local with EmitReadList
+                using(Compiler.Local oldLen = AppendToCollection ? new ProtoBuf.Compiler.Local(ctx, ctx.MapType(typeof(int))) : null) {
+                    Type[] copyToArrayInt32Args = new Type[] { ctx.MapType(typeof(Array)), ctx.MapType(typeof(int)) };
+
+                    if (AppendToCollection)
+                    {
+                        ctx.LoadLength(oldArr, true);
+                        ctx.CopyValue();
+                        ctx.StoreValue(oldLen);
+
+                        ctx.LoadAddress(list, listType);
+                        ctx.LoadValue(listType.GetProperty("Count"));
+                        ctx.Add();
+                        ctx.CreateArray(itemType, null); // length is on the stack
+                        ctx.StoreValue(newArr);
+
+                        ctx.LoadValue(oldLen);
+                        Compiler.CodeLabel nothingToCopy = ctx.DefineLabel();
+                        ctx.BranchIfFalse(nothingToCopy, true);
+                        ctx.LoadValue(oldArr);
+                        ctx.LoadValue(newArr);
+                        ctx.LoadValue(0); // index in target
+
+                        ctx.EmitCall(expected.GetMethod("CopyTo", copyToArrayInt32Args));
+                        ctx.MarkLabel(nothingToCopy);
+
+                        ctx.LoadValue(list);
+                        ctx.LoadValue(newArr);
+                        ctx.LoadValue(oldLen);
+                        
+                    }
+                    else
+                    {
+                        ctx.LoadAddress(list, listType);
+                        ctx.LoadValue(listType.GetProperty("Count"));
+                        ctx.CreateArray(itemType, null);
+                        ctx.StoreValue(newArr);
+
+                        ctx.LoadAddress(list, listType);
+                        ctx.LoadValue(newArr);
+                        ctx.LoadValue(0);
+                    }
+
+                    copyToArrayInt32Args[0] = expected; // // prefer: CopyTo(T[], int)
+                    MethodInfo copyTo = listType.GetMethod("CopyTo", copyToArrayInt32Args);
+                    if (copyTo == null)
+                    { // fallback: CopyTo(Array, int)
+                        copyToArrayInt32Args[1] = ctx.MapType(typeof(Array));
+                        copyTo = listType.GetMethod("CopyTo", copyToArrayInt32Args);
+                    }
+                    ctx.EmitCall(copyTo);
+                }
+                ctx.LoadValue(newArr);
+            }
+
+
+        }
+#endif
+    }
+}
+#endif

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/Serializers/ArrayDecorator.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: f0f11c89e09398a4db960106c8bd0fcc
+timeCreated: 1515899114
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 64 - 0
Unity/Assets/Plugins/protobuf-net/Serializers/BlobSerializer.cs

@@ -0,0 +1,64 @@
+#if !NO_RUNTIME
+using System;
+#if FEAT_COMPILER
+using System.Reflection.Emit;
+#endif
+
+#if FEAT_IKVM
+using Type = IKVM.Reflection.Type;
+#endif
+
+
+namespace ProtoBuf.Serializers
+{
+    sealed class BlobSerializer : IProtoSerializer
+    {
+        public Type ExpectedType { get { return expectedType; } }
+
+#if FEAT_IKVM
+        readonly Type expectedType;
+#else
+        static readonly Type expectedType = typeof(byte[]);
+#endif
+        public BlobSerializer(ProtoBuf.Meta.TypeModel model, bool overwriteList)
+        {
+#if FEAT_IKVM
+            expectedType = model.MapType(typeof(byte[]));
+#endif
+            this.overwriteList = overwriteList;
+        }
+        private readonly bool overwriteList;
+#if !FEAT_IKVM
+        public object Read(object value, ProtoReader source)
+        {
+            return ProtoReader.AppendBytes(overwriteList ? null : (byte[])value, source);
+        }
+        public void Write(object value, ProtoWriter dest)
+        {
+            ProtoWriter.WriteBytes((byte[])value, dest);
+        }
+#endif
+        bool IProtoSerializer.RequiresOldValue { get { return !overwriteList; } }
+        bool IProtoSerializer.ReturnsValue { get { return true; } }
+#if FEAT_COMPILER
+        void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
+        {
+            ctx.EmitBasicWrite("WriteBytes", valueFrom);
+        }
+        void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
+        {
+            if (overwriteList)
+            {
+                ctx.LoadNullRef();
+            }
+            else
+            {
+                ctx.LoadValue(valueFrom);
+            }
+            ctx.LoadReaderWriter();
+            ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("AppendBytes"));
+        }
+#endif
+    }
+}
+#endif

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/Serializers/BlobSerializer.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 1458f6dbd20d0b04891380a26656a6a4
+timeCreated: 1515899112
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 57 - 0
Unity/Assets/Plugins/protobuf-net/Serializers/BooleanSerializer.cs

@@ -0,0 +1,57 @@
+#if !NO_RUNTIME
+using System;
+
+#if FEAT_IKVM
+using Type = IKVM.Reflection.Type;
+using IKVM.Reflection;
+#else
+using System.Reflection;
+#endif
+
+
+
+
+
+namespace ProtoBuf.Serializers
+{
+    sealed class BooleanSerializer : IProtoSerializer
+    {
+#if FEAT_IKVM
+        readonly Type expectedType;
+#else
+        static readonly Type expectedType = typeof(bool);
+#endif
+        public BooleanSerializer(ProtoBuf.Meta.TypeModel model)
+        {
+#if FEAT_IKVM
+            expectedType = model.MapType(typeof(bool));
+#endif
+        }
+        public Type ExpectedType { get { return expectedType; } }
+
+#if !FEAT_IKVM
+        public void Write(object value, ProtoWriter dest)
+        {
+            ProtoWriter.WriteBoolean((bool)value, dest);
+        }
+        public object Read(object value, ProtoReader source)
+        {
+            Helpers.DebugAssert(value == null); // since replaces
+            return source.ReadBoolean();
+        }
+#endif
+        bool IProtoSerializer.RequiresOldValue { get { return false; } }
+        bool IProtoSerializer.ReturnsValue { get { return true; } }
+#if FEAT_COMPILER
+        void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
+        {
+            ctx.EmitBasicWrite("WriteBoolean", valueFrom);
+        }
+        void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
+        {
+            ctx.EmitBasicRead("ReadBoolean", ExpectedType);
+        }
+#endif
+    }
+}
+#endif

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/Serializers/BooleanSerializer.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 4c52ca13eaa985f4b874f6e93fe0569d
+timeCreated: 1515899112
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 54 - 0
Unity/Assets/Plugins/protobuf-net/Serializers/ByteSerializer.cs

@@ -0,0 +1,54 @@
+#if !NO_RUNTIME
+using System;
+
+#if FEAT_IKVM
+using Type = IKVM.Reflection.Type;
+#endif
+
+
+
+namespace ProtoBuf.Serializers
+{
+    sealed class ByteSerializer : IProtoSerializer
+    {
+        public Type ExpectedType { get { return expectedType; } }
+
+#if FEAT_IKVM
+        readonly Type expectedType;
+#else
+        static readonly Type expectedType = typeof(byte);
+#endif
+        public ByteSerializer(ProtoBuf.Meta.TypeModel model)
+        {
+#if FEAT_IKVM
+            expectedType = model.MapType(typeof(byte));
+#endif
+        }
+        bool IProtoSerializer.RequiresOldValue { get { return false; } }
+        bool IProtoSerializer.ReturnsValue { get { return true; } }
+#if !FEAT_IKVM
+        public void Write(object value, ProtoWriter dest)
+        {
+            ProtoWriter.WriteByte((byte)value, dest);
+        }
+        public object Read(object value, ProtoReader source)
+        {
+            Helpers.DebugAssert(value == null); // since replaces
+            return source.ReadByte();
+        }
+#endif
+
+#if FEAT_COMPILER
+        void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
+        {
+            ctx.EmitBasicWrite("WriteByte", valueFrom);
+        }
+        void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
+        {
+            ctx.EmitBasicRead("ReadByte", ExpectedType);
+        }
+#endif
+
+    }
+}
+#endif

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/Serializers/ByteSerializer.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: ff2d8c29190fa8a498f367e18f01c37b
+timeCreated: 1515899114
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 44 - 0
Unity/Assets/Plugins/protobuf-net/Serializers/CharSerializer.cs

@@ -0,0 +1,44 @@
+#if !NO_RUNTIME
+using System;
+
+#if FEAT_IKVM
+using Type = IKVM.Reflection.Type;
+using IKVM.Reflection;
+#else
+using System.Reflection;
+#endif
+
+
+namespace ProtoBuf.Serializers
+{
+    sealed class CharSerializer : UInt16Serializer
+    {
+#if FEAT_IKVM
+        readonly Type expectedType;
+#else
+        static readonly Type expectedType = typeof(char);
+#endif
+        public CharSerializer(ProtoBuf.Meta.TypeModel model) : base(model)
+        {
+#if FEAT_IKVM
+            expectedType = model.MapType(typeof(char));
+#endif
+        }
+        public override Type ExpectedType { get { return expectedType; } }
+
+#if !FEAT_IKVM
+        public override void Write(object value, ProtoWriter dest)
+        {
+            ProtoWriter.WriteUInt16((ushort)(char)value, dest);
+        }
+        public override object Read(object value, ProtoReader source)
+        {
+            Helpers.DebugAssert(value == null); // since replaces
+            return (char)source.ReadUInt16();
+        }
+#endif
+        // no need for any special IL here; ushort and char are
+        // interchangeable as long as there is no boxing/unboxing
+    }
+}
+#endif

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/Serializers/CharSerializer.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 6f278d38e848e6147a379f0e85cbb10f
+timeCreated: 1515899113
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 78 - 0
Unity/Assets/Plugins/protobuf-net/Serializers/CompiledSerializer.cs

@@ -0,0 +1,78 @@
+#if FEAT_COMPILER && !(FX11 || FEAT_IKVM)
+using System;
+using ProtoBuf.Meta;
+
+
+
+namespace ProtoBuf.Serializers
+{
+    sealed class CompiledSerializer : IProtoTypeSerializer
+    {
+        bool IProtoTypeSerializer.HasCallbacks(TypeModel.CallbackType callbackType)
+        {
+            return head.HasCallbacks(callbackType); // these routes only used when bits of the model not compiled
+        }
+        bool IProtoTypeSerializer.CanCreateInstance()
+        {
+            return head.CanCreateInstance();
+        }
+        object IProtoTypeSerializer.CreateInstance(ProtoReader source)
+        {
+            return head.CreateInstance(source);
+        }
+        public void Callback(object value, TypeModel.CallbackType callbackType, SerializationContext context)
+        {
+            head.Callback(value, callbackType, context); // these routes only used when bits of the model not compiled
+        }
+        public static CompiledSerializer Wrap(IProtoTypeSerializer head, TypeModel model)
+        {
+            CompiledSerializer result = head as CompiledSerializer;
+            if (result == null)
+            {
+                result = new CompiledSerializer(head, model);
+                Helpers.DebugAssert(((IProtoTypeSerializer)result).ExpectedType == head.ExpectedType);
+            }
+            return result;
+        }
+        private readonly IProtoTypeSerializer head;
+        private readonly Compiler.ProtoSerializer serializer;
+        private readonly Compiler.ProtoDeserializer deserializer;
+        private CompiledSerializer(IProtoTypeSerializer head, TypeModel model)
+        {
+            this.head = head;
+            serializer = Compiler.CompilerContext.BuildSerializer(head, model);
+            deserializer = Compiler.CompilerContext.BuildDeserializer(head, model);
+        }
+        bool IProtoSerializer.RequiresOldValue { get { return head.RequiresOldValue; } }
+        bool IProtoSerializer.ReturnsValue { get { return head.ReturnsValue; } }
+
+        Type IProtoSerializer.ExpectedType { get { return head.ExpectedType; } }
+
+        void IProtoSerializer.Write(object value, ProtoWriter dest)
+        {
+            serializer(value, dest);
+        }
+        object IProtoSerializer.Read(object value, ProtoReader source)
+        {
+            return deserializer(value, source);
+        }
+
+        void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
+        {
+            head.EmitWrite(ctx, valueFrom);
+        }
+        void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
+        {
+            head.EmitRead(ctx, valueFrom);
+        }
+        void IProtoTypeSerializer.EmitCallback(Compiler.CompilerContext ctx, Compiler.Local valueFrom, TypeModel.CallbackType callbackType)
+        {
+            head.EmitCallback(ctx, valueFrom, callbackType);
+        }
+        void IProtoTypeSerializer.EmitCreateInstance(Compiler.CompilerContext ctx)
+        {
+            head.EmitCreateInstance(ctx);
+        }
+    }
+}
+#endif

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/Serializers/CompiledSerializer.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 9a90f9f63dac5af4eb97f221c6582131
+timeCreated: 1515899113
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 55 - 0
Unity/Assets/Plugins/protobuf-net/Serializers/DateTimeSerializer.cs

@@ -0,0 +1,55 @@
+#if !NO_RUNTIME
+using System;
+
+#if FEAT_IKVM
+using Type = IKVM.Reflection.Type;
+using IKVM.Reflection;
+#else
+using System.Reflection;
+#endif
+
+namespace ProtoBuf.Serializers
+{
+    sealed class DateTimeSerializer : IProtoSerializer
+    {
+#if FEAT_IKVM
+        readonly Type expectedType;
+#else
+        static readonly Type expectedType = typeof(DateTime);
+#endif
+        public Type ExpectedType { get { return expectedType; } }
+
+        bool IProtoSerializer.RequiresOldValue { get { return false; } }
+        bool IProtoSerializer.ReturnsValue { get { return true; } }
+
+        public DateTimeSerializer(ProtoBuf.Meta.TypeModel model)
+        {
+#if FEAT_IKVM
+            expectedType = model.MapType(typeof(DateTime));
+#endif
+        }
+#if !FEAT_IKVM
+        public object Read(object value, ProtoReader source)
+        {
+            Helpers.DebugAssert(value == null); // since replaces
+            return BclHelpers.ReadDateTime(source);
+        }
+        public void Write(object value, ProtoWriter dest)
+        {
+            BclHelpers.WriteDateTime((DateTime)value, dest);
+        }
+#endif
+#if FEAT_COMPILER
+        void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
+        {
+            ctx.EmitWrite(ctx.MapType(typeof(BclHelpers)), "WriteDateTime", valueFrom);
+        }
+        void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
+        {
+            ctx.EmitBasicRead(ctx.MapType(typeof(BclHelpers)), "ReadDateTime", ExpectedType);
+        }
+#endif
+
+    }
+}
+#endif

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/Serializers/DateTimeSerializer.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 5c90349d662e6774ab6d0cefff7a8b63
+timeCreated: 1515899112
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 57 - 0
Unity/Assets/Plugins/protobuf-net/Serializers/DecimalSerializer.cs

@@ -0,0 +1,57 @@
+#if !NO_RUNTIME
+using System;
+using ProtoBuf.Meta;
+
+#if FEAT_IKVM
+using Type = IKVM.Reflection.Type;
+using IKVM.Reflection;
+#else
+using System.Reflection;
+#endif
+
+
+
+namespace ProtoBuf.Serializers
+{
+    sealed class DecimalSerializer : IProtoSerializer
+    {
+        #if FEAT_IKVM
+        readonly Type expectedType;
+#else
+        static readonly Type expectedType = typeof(decimal);
+#endif
+        public DecimalSerializer(ProtoBuf.Meta.TypeModel model)
+        {
+#if FEAT_IKVM
+            expectedType = model.MapType(typeof(decimal));
+#endif
+        }
+        public Type ExpectedType { get { return expectedType; } }
+
+        bool IProtoSerializer.RequiresOldValue { get { return false; } }
+        bool IProtoSerializer.ReturnsValue { get { return true; } }
+#if !FEAT_IKVM
+        public object Read(object value, ProtoReader source)
+        {
+            Helpers.DebugAssert(value == null); // since replaces
+            return BclHelpers.ReadDecimal(source);
+        }
+        public void Write(object value, ProtoWriter dest)
+        {
+            BclHelpers.WriteDecimal((decimal)value, dest);
+        }
+#endif
+#if FEAT_COMPILER
+        void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
+        {
+            ctx.EmitWrite(ctx.MapType(typeof(BclHelpers)), "WriteDecimal", valueFrom);
+        }
+        void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
+        {
+            ctx.EmitBasicRead(ctx.MapType(typeof(BclHelpers)), "ReadDecimal", ExpectedType);
+        }
+#endif
+
+    }
+}
+#endif

+ 12 - 0
Unity/Assets/Plugins/protobuf-net/Serializers/DecimalSerializer.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 1574ba751317e4047b0d0140e18629f1
+timeCreated: 1515899112
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio