Просмотр исходного кода

protobuf使用google.protobuf3.0的库

tanghai 7 лет назад
Родитель
Сommit
d39fd7257b
100 измененных файлов с 11593 добавлено и 1339 удалено
  1. 15 0
      Client-Server.sln
  2. 19 0
      Proto/FrameMessage.proto
  3. 31 10
      Proto/HotfixMessage.proto
  4. 38 19
      Proto/OuterMessage.proto
  5. 1 1
      Server/App/Program.cs
  6. 1 1
      Server/Hotfix/Handler/Actor_TestRequestHandler.cs
  7. 28 28
      Server/Hotfix/Handler/C2M_ReloadHandler.cs
  8. 1 0
      Server/Hotfix/Module/FrameSync/G2M_CreateUnitHandler.cs
  9. 1 1
      Server/Hotfix/Module/FrameSync/ServerFrameComponentSystem.cs
  10. 0 148
      Server/Hotfix/Module/Message/HotfixMessage.cs
  11. 0 16
      Server/Hotfix/Module/Message/HotfixOpcode.cs
  12. 0 142
      Server/Hotfix/Module/Message/InnerMessage.cs
  13. 3 0
      Server/Hotfix/Module/Message/InnerOpcode.cs
  14. 2 2
      Server/Hotfix/Module/Message/NetOuterComponentSystem.cs
  15. 0 219
      Server/Hotfix/Module/Message/OuterMessage.cs
  16. 3 2
      Server/Hotfix/Module/Message/OuterMessageDispatcher.cs
  17. 0 21
      Server/Hotfix/Module/Message/OuterOpcode.cs
  18. 6 0
      Server/Hotfix/Server.Hotfix.csproj
  19. 1 9
      Server/Model/Module/Actor/ActorResponse.cs
  20. 2 32
      Server/Model/Module/Message/MongoPacker.cs
  21. 3 2
      Server/Model/Server.Model.csproj
  22. 79 0
      Server/ThirdParty/Google.Protobuf/ByteArray.cs
  23. 378 0
      Server/ThirdParty/Google.Protobuf/ByteString.cs
  24. 1274 0
      Server/ThirdParty/Google.Protobuf/CodedInputStream.cs
  25. 304 0
      Server/ThirdParty/Google.Protobuf/CodedOutputStream.ComputeSize.cs
  26. 761 0
      Server/ThirdParty/Google.Protobuf/CodedOutputStream.cs
  27. 580 0
      Server/ThirdParty/Google.Protobuf/Collections/RepeatedField.cs
  28. 64 0
      Server/ThirdParty/Google.Protobuf/Compatibility/PropertyInfoExtensions.cs
  29. 64 0
      Server/ThirdParty/Google.Protobuf/Compatibility/StreamExtensions.cs
  30. 379 0
      Server/ThirdParty/Google.Protobuf/FieldCodec.cs
  31. 11 0
      Server/ThirdParty/Google.Protobuf/Google.Protobuf.csproj
  32. 69 0
      Server/ThirdParty/Google.Protobuf/ICustomDiagnosticMessage.cs
  33. 64 0
      Server/ThirdParty/Google.Protobuf/IMessage.cs
  34. 129 0
      Server/ThirdParty/Google.Protobuf/InvalidProtocolBufferException.cs
  35. 110 0
      Server/ThirdParty/Google.Protobuf/LimitedInputStream.cs
  36. 171 0
      Server/ThirdParty/Google.Protobuf/MessageExtensions.cs
  37. 241 0
      Server/ThirdParty/Google.Protobuf/MessageParser.cs
  38. 12 0
      Server/ThirdParty/Google.Protobuf/Program.cs
  39. 79 0
      Server/ThirdParty/Google.Protobuf/ProtoPreconditions.cs
  40. 104 0
      Server/ThirdParty/Google.Protobuf/WireFormat.cs
  41. 38 233
      Unity/Assets/Editor/Proto2CsEditor/Proto2CSEditor.cs
  42. 0 98
      Unity/Assets/Scripts/Base/Helper/ProtobufHelper.cs
  43. 0 24
      Unity/Assets/Scripts/Helper/ILHelper.cs
  44. 2 0
      Unity/Assets/Scripts/Init.cs
  45. 6 6
      Unity/Assets/Scripts/Module/FrameSync/ClientFrameComponent.cs
  46. 22 25
      Unity/Assets/Scripts/Module/FrameSync/FrameMessage.cs
  47. 213 0
      Unity/Assets/Scripts/Module/FrameSync/FrameProto.cs
  48. 2 3
      Unity/Assets/Scripts/Module/FrameSync/FrameProto.cs.meta
  49. 1 6
      Unity/Assets/Scripts/Module/Message/IActorMessage.cs
  50. 1 3
      Unity/Assets/Scripts/Module/Message/IMessage.cs
  51. 1 9
      Unity/Assets/Scripts/Module/Message/IMessagePacker.cs
  52. 1 1
      Unity/Assets/Scripts/Module/Message/NetOuterComponent.cs
  53. 1018 218
      Unity/Assets/Scripts/Module/Message/OuterMessage.cs
  54. 46 5
      Unity/Assets/Scripts/Module/Message/OuterOpcode.cs
  55. 43 0
      Unity/Assets/Scripts/Module/Message/ProtobufHelper.cs
  56. 0 0
      Unity/Assets/Scripts/Module/Message/ProtobufHelper.cs.meta
  57. 2 32
      Unity/Assets/Scripts/Module/Message/ProtobufPacker.cs
  58. 0 1
      Unity/Assets/Scripts/Module/Message/Session.cs
  59. 2 3
      Unity/Assets/ThirdParty/Google.Protobuf.meta
  60. 74 0
      Unity/Assets/ThirdParty/Google.Protobuf/AdaptHelper.cs
  61. 2 3
      Unity/Assets/ThirdParty/Google.Protobuf/AdaptHelper.cs.meta
  62. 57 0
      Unity/Assets/ThirdParty/Google.Protobuf/Adapt_IMessage.cs
  63. 2 3
      Unity/Assets/ThirdParty/Google.Protobuf/Adapt_IMessage.cs.meta
  64. 79 0
      Unity/Assets/ThirdParty/Google.Protobuf/ByteArray.cs
  65. 2 3
      Unity/Assets/ThirdParty/Google.Protobuf/ByteArray.cs.meta
  66. 378 0
      Unity/Assets/ThirdParty/Google.Protobuf/ByteString.cs
  67. 11 0
      Unity/Assets/ThirdParty/Google.Protobuf/ByteString.cs.meta
  68. 1274 0
      Unity/Assets/ThirdParty/Google.Protobuf/CodedInputStream.cs
  69. 11 0
      Unity/Assets/ThirdParty/Google.Protobuf/CodedInputStream.cs.meta
  70. 304 0
      Unity/Assets/ThirdParty/Google.Protobuf/CodedOutputStream.ComputeSize.cs
  71. 11 0
      Unity/Assets/ThirdParty/Google.Protobuf/CodedOutputStream.ComputeSize.cs.meta
  72. 761 0
      Unity/Assets/ThirdParty/Google.Protobuf/CodedOutputStream.cs
  73. 11 0
      Unity/Assets/ThirdParty/Google.Protobuf/CodedOutputStream.cs.meta
  74. 2 3
      Unity/Assets/ThirdParty/Google.Protobuf/Collections.meta
  75. 580 0
      Unity/Assets/ThirdParty/Google.Protobuf/Collections/RepeatedField.cs
  76. 11 0
      Unity/Assets/ThirdParty/Google.Protobuf/Collections/RepeatedField.cs.meta
  77. 2 3
      Unity/Assets/ThirdParty/Google.Protobuf/Compatibility.meta
  78. 64 0
      Unity/Assets/ThirdParty/Google.Protobuf/Compatibility/PropertyInfoExtensions.cs
  79. 11 0
      Unity/Assets/ThirdParty/Google.Protobuf/Compatibility/PropertyInfoExtensions.cs.meta
  80. 64 0
      Unity/Assets/ThirdParty/Google.Protobuf/Compatibility/StreamExtensions.cs
  81. 11 0
      Unity/Assets/ThirdParty/Google.Protobuf/Compatibility/StreamExtensions.cs.meta
  82. 379 0
      Unity/Assets/ThirdParty/Google.Protobuf/FieldCodec.cs
  83. 11 0
      Unity/Assets/ThirdParty/Google.Protobuf/FieldCodec.cs.meta
  84. 69 0
      Unity/Assets/ThirdParty/Google.Protobuf/ICustomDiagnosticMessage.cs
  85. 11 0
      Unity/Assets/ThirdParty/Google.Protobuf/ICustomDiagnosticMessage.cs.meta
  86. 64 0
      Unity/Assets/ThirdParty/Google.Protobuf/IMessage.cs
  87. 11 0
      Unity/Assets/ThirdParty/Google.Protobuf/IMessage.cs.meta
  88. 129 0
      Unity/Assets/ThirdParty/Google.Protobuf/InvalidProtocolBufferException.cs
  89. 11 0
      Unity/Assets/ThirdParty/Google.Protobuf/InvalidProtocolBufferException.cs.meta
  90. 110 0
      Unity/Assets/ThirdParty/Google.Protobuf/LimitedInputStream.cs
  91. 11 0
      Unity/Assets/ThirdParty/Google.Protobuf/LimitedInputStream.cs.meta
  92. 171 0
      Unity/Assets/ThirdParty/Google.Protobuf/MessageExtensions.cs
  93. 11 0
      Unity/Assets/ThirdParty/Google.Protobuf/MessageExtensions.cs.meta
  94. 241 0
      Unity/Assets/ThirdParty/Google.Protobuf/MessageParser.cs
  95. 11 0
      Unity/Assets/ThirdParty/Google.Protobuf/MessageParser.cs.meta
  96. 79 0
      Unity/Assets/ThirdParty/Google.Protobuf/ProtoPreconditions.cs
  97. 11 0
      Unity/Assets/ThirdParty/Google.Protobuf/ProtoPreconditions.cs.meta
  98. 104 0
      Unity/Assets/ThirdParty/Google.Protobuf/WireFormat.cs
  99. 11 0
      Unity/Assets/ThirdParty/Google.Protobuf/WireFormat.cs.meta
  100. 0 4
      Unity/Assets/ThirdParty/ILRuntime/Generated/CLRBindings.cs

+ 15 - 0
Client-Server.sln

@@ -33,6 +33,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MongoDB.Driver", "Server\Th
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MongoDB.Driver.Core", "Server\ThirdParty\MongodbDriver\DotNetCoreDriver\MongoDB.Driver.Core\MongoDB.Driver.Core.csproj", "{831276B2-B7EB-4FD0-93E5-4D2109C78950}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Google.Protobuf", "Server\ThirdParty\Google.Protobuf\Google.Protobuf.csproj", "{BC06C46E-79F3-4AB6-800E-FA080CA54A0B}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -175,6 +177,18 @@ Global
 		{831276B2-B7EB-4FD0-93E5-4D2109C78950}.Release|x64.Build.0 = Release|Any CPU
 		{831276B2-B7EB-4FD0-93E5-4D2109C78950}.Release|x86.ActiveCfg = Release|Any CPU
 		{831276B2-B7EB-4FD0-93E5-4D2109C78950}.Release|x86.Build.0 = Release|Any CPU
+		{BC06C46E-79F3-4AB6-800E-FA080CA54A0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{BC06C46E-79F3-4AB6-800E-FA080CA54A0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{BC06C46E-79F3-4AB6-800E-FA080CA54A0B}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{BC06C46E-79F3-4AB6-800E-FA080CA54A0B}.Debug|x64.Build.0 = Debug|Any CPU
+		{BC06C46E-79F3-4AB6-800E-FA080CA54A0B}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{BC06C46E-79F3-4AB6-800E-FA080CA54A0B}.Debug|x86.Build.0 = Debug|Any CPU
+		{BC06C46E-79F3-4AB6-800E-FA080CA54A0B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{BC06C46E-79F3-4AB6-800E-FA080CA54A0B}.Release|Any CPU.Build.0 = Release|Any CPU
+		{BC06C46E-79F3-4AB6-800E-FA080CA54A0B}.Release|x64.ActiveCfg = Release|Any CPU
+		{BC06C46E-79F3-4AB6-800E-FA080CA54A0B}.Release|x64.Build.0 = Release|Any CPU
+		{BC06C46E-79F3-4AB6-800E-FA080CA54A0B}.Release|x86.ActiveCfg = Release|Any CPU
+		{BC06C46E-79F3-4AB6-800E-FA080CA54A0B}.Release|x86.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -193,6 +207,7 @@ Global
 		{BC611535-3BDA-45C5-8765-9E242E312B8F} = {4940CE10-6652-4AC6-9D30-CF200A217643}
 		{6D19C1F8-085C-422E-8DAF-2E49024DB08C} = {4940CE10-6652-4AC6-9D30-CF200A217643}
 		{831276B2-B7EB-4FD0-93E5-4D2109C78950} = {4940CE10-6652-4AC6-9D30-CF200A217643}
+		{BC06C46E-79F3-4AB6-800E-FA080CA54A0B} = {78640FA0-9F11-412D-A639-61F03D02407A}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {EABC01E3-3EB5-47EF-B46E-AAD8BB3585F1}

+ 19 - 0
Proto/FrameMessage.proto

@@ -0,0 +1,19 @@
+syntax = "proto3";
+package ETModel;
+
+message OneFrameMessage // IActorMessage
+{
+	int32 RpcId = 90;
+	int64 ActorId = 93;
+	int32 Op = 1;
+	bytes AMessage = 2;
+}
+
+message FrameMessage // IActorMessage
+{
+	int32 RpcId = 90;
+	int64 ActorId = 93;
+
+	int32 Frame = 1;
+	repeated OneFrameMessage Message = 2;
+}

+ 31 - 10
Proto/HotfixMessage.proto

@@ -1,49 +1,70 @@
+syntax = "proto3";
+package ETHotfix;
+
 message C2R_Login // IRequest
 {
-	required string	Account	 = 1;	// 帐号
-	required string	Password = 2;	// 密码
+	int32 RpcId = 90;
+	string	Account	 = 1;	// 帐号
+	string	Password = 2;	// 密码
 }
 
 message R2C_Login // IResponse
 {
-	required string Address = 1;
-	required int64 	Key	    = 2;
+	int32 RpcId = 90;
+	int32 Error = 91;
+	string Message = 92;
+	string Address = 1;
+	int64 Key	    = 2;
 }
 
 message C2G_LoginGate // IRequest
 {
-	required int64 Key = 1;	// 帐号
+	int32 RpcId = 90;
+	int64 Key = 1;	// 帐号
 }
 
 message G2C_LoginGate // IResponse
 {
-	required int64 PlayerId = 1;
+	int32 RpcId = 90;
+	int32 Error = 91;
+	string Message = 92;
+	int64 PlayerId = 1;
 }
 
 message G2C_TestHotfixMessage // IMessage
 {
-	required string Info = 1;
+	string Info = 1;
 }
 
 message C2M_TestActorRequest // IActorRequest
 {
-	required string Info = 1;
+	int32 RpcId = 90;
+	int64 ActorId = 91;
+	string Info = 1;
 }
 
 message M2C_TestActorResponse // IActorResponse
 {
-	required string Info = 1;
+	int32 RpcId = 90;
+	int32 Error = 91;
+	string Message = 92;
+	string Info = 1;
 }
 
 message PlayerInfo // IMessage
 {
+	int32 RpcId = 90;
 }
 
 message C2G_PlayerInfo // IRequest
 {
+	int32 RpcId = 90;
 }
 
 message G2C_PlayerInfo // IResponse
 {
-	repeated PlayerInfo PlayerInfos = 1;
+	int32 RpcId = 90;
+	int32 Error = 91;
+	string Message = 92;
+	PlayerInfo PlayerInfos = 1;
 }

+ 38 - 19
Proto/OuterMessage.proto

@@ -1,70 +1,89 @@
+syntax = "proto3";
+package ETModel;
+
 message Actor_Test // IActorMessage
 {
-	required string Info = 1;
+	int32 RpcId = 90;
+	int64 ActorId = 93;
+	string Info = 1;
 }
 
 message Actor_TestRequest // IActorRequest
 {
-	required string request = 1;
+	int32 RpcId = 90;
+	int64 ActorId = 93;
+	string request = 1;
 }
 
 message Actor_TestResponse // IActorResponse
 {
-	required string response = 1;
+	int32 RpcId = 90;
+	int32 Error = 91;
+	string Message = 92;
+	string response = 1;
 }
 
 message Actor_TransferRequest // IActorRequest
 {
-	required int32 MapIndex = 1;
+	int32 RpcId = 90;
+	int64 ActorId = 93;
+	int32 MapIndex = 1;
 }
 
 message Actor_TransferResponse // IActorResponse
 {
+	int32 RpcId = 90;
+	int32 Error = 91;
+	string Message = 92;
 }
 
 message C2G_EnterMap // IRequest
 {
+	int32 RpcId = 90;
 }
 
 message G2C_EnterMap // IResponse
 {
-	required int64 UnitId = 1;
-	required int32 Count  = 2;
+	int32 RpcId = 90;
+	int32 Error = 91;
+	string Message = 92;
+	int64 UnitId = 1;
+	int32 Count  = 2;
 }
 
 message UnitInfo
 {
-	required int64 UnitId  = 1;
-	required int32 X       = 2;
-	required int32 Z       = 3;
+	int64 UnitId  = 1;
+	int32 X       = 2;
+	int32 Z       = 3;
 }
 
 message Actor_CreateUnits // IActorMessage
 {
+	int32 RpcId = 90;
+	int64 ActorId = 93;
     repeated UnitInfo Units = 1;
 }
 
 message Frame_ClickMap // IFrameMessage
 {
-	required int32 X = 1;
-	required int32 Z = 2;
-}
-
-message C2M_Reload // IRequest
-{
-	required AppType AppType = 1;
+	int32 RpcId = 90;
+	int64 Id = 94;
+	int32 X = 1;
+	int32 Z = 2;
 }
 
-message M2C_Reload // IResponse
-{
-}
 
 message C2R_Ping // IRequest
 {
+	int32 RpcId = 90;
 }
 
 message R2C_Ping // IResponse
 {
+	int32 RpcId = 90;
+	int32 Error = 91;
+	string Message = 92;
 }
 
 message G2C_Test // IMessage

+ 1 - 1
Server/App/Program.cs

@@ -14,7 +14,7 @@ namespace App
 			SynchronizationContext.SetSynchronizationContext(OneThreadSynchronizationContext.Instance);
 			
 			try
-			{
+			{			
 				Game.EventSystem.Add(DLLType.Model, typeof(Game).Assembly);
 				Game.EventSystem.Add(DLLType.Hotfix, DllHelper.GetHotfixAssembly());
 

+ 1 - 1
Server/Hotfix/Handler/Actor_TestRequestHandler.cs

@@ -10,7 +10,7 @@ namespace ETHotfix
 		protected override async Task Run(Unit unit, Actor_TestRequest message, Action<Actor_TestResponse> reply)
 		{
 			await Task.CompletedTask;
-			reply(new Actor_TestResponse() {response = "response actor rpc"});
+			reply(new Actor_TestResponse() {Response = "response actor rpc"});
 		}
 	}
 }

+ 28 - 28
Server/Hotfix/Handler/C2M_ReloadHandler.cs

@@ -3,32 +3,32 @@ using ETModel;
 
 namespace ETHotfix
 {
-	[MessageHandler(AppType.Manager)]
-	public class C2M_ReloadHandler: AMRpcHandler<C2M_Reload, M2C_Reload>
-	{
-		protected override async void Run(Session session, C2M_Reload message, Action<M2C_Reload> reply)
-		{
-			M2C_Reload response = new M2C_Reload();
-			try
-			{
-				StartConfigComponent startConfigComponent = Game.Scene.GetComponent<StartConfigComponent>();
-				NetInnerComponent netInnerComponent = Game.Scene.GetComponent<NetInnerComponent>();
-				foreach (StartConfig startConfig in startConfigComponent.GetAll())
-				{
-					if (!message.AppType.Is(startConfig.AppType))
-					{
-						continue;
-					}
-					InnerConfig innerConfig = startConfig.GetComponent<InnerConfig>();
-					Session serverSession = netInnerComponent.Get(innerConfig.IPEndPoint);
-					await serverSession.Call(new M2A_Reload());
-				}
-				reply(response);
-			}
-			catch (Exception e)
-			{
-				ReplyError(response, e, reply);
-			}
-		}
-	}
+	//[MessageHandler(AppType.Manager)]
+	//public class C2M_ReloadHandler: AMRpcHandler<C2M_Reload, M2C_Reload>
+	//{
+	//	protected override async void Run(Session session, C2M_Reload message, Action<M2C_Reload> reply)
+	//	{
+	//		M2C_Reload response = new M2C_Reload();
+	//		try
+	//		{
+	//			StartConfigComponent startConfigComponent = Game.Scene.GetComponent<StartConfigComponent>();
+	//			NetInnerComponent netInnerComponent = Game.Scene.GetComponent<NetInnerComponent>();
+	//			foreach (StartConfig startConfig in startConfigComponent.GetAll())
+	//			{
+	//				if (!message.AppType.Is(startConfig.AppType))
+	//				{
+	//					continue;
+	//				}
+	//				InnerConfig innerConfig = startConfig.GetComponent<InnerConfig>();
+	//				Session serverSession = netInnerComponent.Get(innerConfig.IPEndPoint);
+	//				await serverSession.Call(new M2A_Reload());
+	//			}
+	//			reply(response);
+	//		}
+	//		catch (Exception e)
+	//		{
+	//			ReplyError(response, e, reply);
+	//		}
+	//	}
+	//}
 }

+ 1 - 0
Server/Hotfix/Module/FrameSync/G2M_CreateUnitHandler.cs

@@ -1,5 +1,6 @@
 using System;
 using ETModel;
+using Google.Protobuf;
 
 namespace ETHotfix
 {

+ 1 - 1
Server/Hotfix/Module/FrameSync/ServerFrameComponentSystem.cs

@@ -45,7 +45,7 @@ namespace ETHotfix
 
         public static void Add(this ServerFrameComponent self, OneFrameMessage oneFrameMessage)
         {
-            self.FrameMessage.Messages.Add(oneFrameMessage);
+            self.FrameMessage.Message.Add(oneFrameMessage);
         }
     }
 }

+ 0 - 148
Server/Hotfix/Module/Message/HotfixMessage.cs

@@ -1,148 +0,0 @@
-using ProtoBuf;
-using ETModel;
-using System.Collections.Generic;
-using MongoDB.Bson.Serialization.Attributes;
-namespace ETHotfix
-{
-	[Message(HotfixOpcode.C2R_Login)]
-	[ProtoContract]
-	public partial class C2R_Login: IRequest
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-		[ProtoMember(1, IsRequired = true)]
-		public string Account;
-
-		[ProtoMember(2, IsRequired = true)]
-		public string Password;
-
-	}
-
-	[Message(HotfixOpcode.R2C_Login)]
-	[ProtoContract]
-	public partial class R2C_Login: IResponse
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-		[ProtoMember(91, IsRequired = true)]
-		public int Error { get; set; }
-
-		[ProtoMember(92, IsRequired = true)]
-		public string Message { get; set; }
-
-		[ProtoMember(1, IsRequired = true)]
-		public string Address;
-
-		[ProtoMember(2, IsRequired = true)]
-		public long Key;
-
-	}
-
-	[Message(HotfixOpcode.C2G_LoginGate)]
-	[ProtoContract]
-	public partial class C2G_LoginGate: IRequest
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-		[ProtoMember(1, IsRequired = true)]
-		public long Key;
-
-	}
-
-	[Message(HotfixOpcode.G2C_LoginGate)]
-	[ProtoContract]
-	public partial class G2C_LoginGate: IResponse
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-		[ProtoMember(91, IsRequired = true)]
-		public int Error { get; set; }
-
-		[ProtoMember(92, IsRequired = true)]
-		public string Message { get; set; }
-
-		[ProtoMember(1, IsRequired = true)]
-		public long PlayerId;
-
-	}
-
-	[Message(HotfixOpcode.G2C_TestHotfixMessage)]
-	[ProtoContract]
-	public partial class G2C_TestHotfixMessage: IMessage
-	{
-		[ProtoMember(1, IsRequired = true)]
-		public string Info;
-
-	}
-
-	[Message(HotfixOpcode.C2M_TestActorRequest)]
-	[ProtoContract]
-	public partial class C2M_TestActorRequest: IActorRequest
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-		[ProtoMember(93, IsRequired = true)]
-		public long ActorId { get; set; }
-
-		[ProtoMember(1, IsRequired = true)]
-		public string Info;
-
-	}
-
-	[Message(HotfixOpcode.M2C_TestActorResponse)]
-	[ProtoContract]
-	public partial class M2C_TestActorResponse: IActorResponse
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-		[ProtoMember(91, IsRequired = true)]
-		public int Error { get; set; }
-
-		[ProtoMember(92, IsRequired = true)]
-		public string Message { get; set; }
-
-		[ProtoMember(1, IsRequired = true)]
-		public string Info;
-
-	}
-
-	[Message(HotfixOpcode.PlayerInfo)]
-	[ProtoContract]
-	public partial class PlayerInfo: IMessage
-	{
-	}
-
-	[Message(HotfixOpcode.C2G_PlayerInfo)]
-	[ProtoContract]
-	public partial class C2G_PlayerInfo: IRequest
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-	}
-
-	[Message(HotfixOpcode.G2C_PlayerInfo)]
-	[ProtoContract]
-	public partial class G2C_PlayerInfo: IResponse
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-		[ProtoMember(91, IsRequired = true)]
-		public int Error { get; set; }
-
-		[ProtoMember(92, IsRequired = true)]
-		public string Message { get; set; }
-
-		[ProtoMember(1)]
-		public List<PlayerInfo> PlayerInfos = new List<PlayerInfo>();
-
-	}
-
-}

+ 0 - 16
Server/Hotfix/Module/Message/HotfixOpcode.cs

@@ -1,16 +0,0 @@
-namespace ETHotfix
-{
-	public static partial class HotfixOpcode
-	{
-		 public const ushort C2R_Login = 10001;
-		 public const ushort R2C_Login = 10002;
-		 public const ushort C2G_LoginGate = 10003;
-		 public const ushort G2C_LoginGate = 10004;
-		 public const ushort G2C_TestHotfixMessage = 10005;
-		 public const ushort C2M_TestActorRequest = 10006;
-		 public const ushort M2C_TestActorResponse = 10007;
-		 public const ushort PlayerInfo = 10008;
-		 public const ushort C2G_PlayerInfo = 10009;
-		 public const ushort G2C_PlayerInfo = 10010;
-	}
-}

+ 0 - 142
Server/Hotfix/Module/Message/InnerMessage.cs

@@ -1,524 +1,382 @@
-using ProtoBuf;
 using ETModel;
 using System.Collections.Generic;
-using MongoDB.Bson.Serialization.Attributes;
 namespace ETHotfix
 {
 /// <summary>
 /// 传送unit
 /// </summary>
 	[Message(InnerOpcode.M2M_TrasferUnitRequest)]
-	[ProtoContract]
 	public partial class M2M_TrasferUnitRequest: IRequest
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
-
-		[ProtoMember(1, IsRequired = true)]
 		public Unit Unit;
 
 	}
 
 	[Message(InnerOpcode.M2M_TrasferUnitResponse)]
-	[ProtoContract]
 	public partial class M2M_TrasferUnitResponse: IResponse
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
 
-		[ProtoMember(91, IsRequired = true)]
 		public int Error { get; set; }
 
-		[ProtoMember(92, IsRequired = true)]
 		public string Message { get; set; }
 
-		[ProtoMember(1, IsRequired = true)]
 		public long InstanceId;
 
 	}
 
 	[Message(InnerOpcode.M2A_Reload)]
-	[ProtoContract]
 	public partial class M2A_Reload: IRequest
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
 
 	}
 
 	[Message(InnerOpcode.A2M_Reload)]
-	[ProtoContract]
 	public partial class A2M_Reload: IResponse
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
 
-		[ProtoMember(91, IsRequired = true)]
 		public int Error { get; set; }
 
-		[ProtoMember(92, IsRequired = true)]
 		public string Message { get; set; }
 
 	}
 
 	[Message(InnerOpcode.G2G_LockRequest)]
-	[ProtoContract]
 	public partial class G2G_LockRequest: IRequest
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
 
-		[ProtoMember(1, IsRequired = true)]
 		public long Id;
 
-		[ProtoMember(2, IsRequired = true)]
 		public string Address;
 
 	}
 
 	[Message(InnerOpcode.G2G_LockResponse)]
-	[ProtoContract]
 	public partial class G2G_LockResponse: IResponse
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
 
-		[ProtoMember(91, IsRequired = true)]
 		public int Error { get; set; }
 
-		[ProtoMember(92, IsRequired = true)]
 		public string Message { get; set; }
 
 	}
 
 	[Message(InnerOpcode.G2G_LockReleaseRequest)]
-	[ProtoContract]
 	public partial class G2G_LockReleaseRequest: IRequest
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
 
-		[ProtoMember(1, IsRequired = true)]
 		public long Id;
 
-		[ProtoMember(2, IsRequired = true)]
 		public string Address;
 
 	}
 
 	[Message(InnerOpcode.G2G_LockReleaseResponse)]
-	[ProtoContract]
 	public partial class G2G_LockReleaseResponse: IResponse
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
 
-		[ProtoMember(91, IsRequired = true)]
 		public int Error { get; set; }
 
-		[ProtoMember(92, IsRequired = true)]
 		public string Message { get; set; }
 
 	}
 
 	[Message(InnerOpcode.DBSaveRequest)]
-	[ProtoContract]
 	public partial class DBSaveRequest: IRequest
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
 
-		[ProtoMember(1, IsRequired = true)]
 		public bool NeedCache;
 
-		[ProtoMember(2, IsRequired = true)]
 		public string CollectionName;
 
-		[ProtoMember(3, IsRequired = true)]
 		public ComponentWithId Component;
 
 	}
 
 	[Message(InnerOpcode.DBSaveBatchResponse)]
-	[ProtoContract]
 	public partial class DBSaveBatchResponse: IResponse
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
 
-		[ProtoMember(91, IsRequired = true)]
 		public int Error { get; set; }
 
-		[ProtoMember(92, IsRequired = true)]
 		public string Message { get; set; }
 
 	}
 
 	[Message(InnerOpcode.DBSaveBatchRequest)]
-	[ProtoContract]
 	public partial class DBSaveBatchRequest: IRequest
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
 
-		[ProtoMember(1, IsRequired = true)]
 		public bool NeedCache;
 
-		[ProtoMember(2, IsRequired = true)]
 		public string CollectionName;
 
-		[ProtoMember(3)]
 		public List<ComponentWithId> Components = new List<ComponentWithId>();
 
 	}
 
 	[Message(InnerOpcode.DBSaveResponse)]
-	[ProtoContract]
 	public partial class DBSaveResponse: IResponse
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
 
-		[ProtoMember(91, IsRequired = true)]
 		public int Error { get; set; }
 
-		[ProtoMember(92, IsRequired = true)]
 		public string Message { get; set; }
 
 	}
 
 	[Message(InnerOpcode.DBQueryRequest)]
-	[ProtoContract]
 	public partial class DBQueryRequest: IRequest
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
 
-		[ProtoMember(1, IsRequired = true)]
 		public long Id;
 
-		[ProtoMember(2, IsRequired = true)]
 		public string CollectionName;
 
-		[ProtoMember(3, IsRequired = true)]
 		public bool NeedCache;
 
 	}
 
 	[Message(InnerOpcode.DBQueryResponse)]
-	[ProtoContract]
 	public partial class DBQueryResponse: IResponse
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
 
-		[ProtoMember(91, IsRequired = true)]
 		public int Error { get; set; }
 
-		[ProtoMember(92, IsRequired = true)]
 		public string Message { get; set; }
 
-		[ProtoMember(1, IsRequired = true)]
 		public ComponentWithId Component;
 
 	}
 
 	[Message(InnerOpcode.DBQueryBatchRequest)]
-	[ProtoContract]
 	public partial class DBQueryBatchRequest: IRequest
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
 
-		[ProtoMember(1, IsRequired = true)]
 		public string CollectionName;
 
-		[ProtoMember(2)]
 		public List<long> IdList = new List<long>();
 
-		[ProtoMember(3, IsRequired = true)]
 		public bool NeedCache;
 
 	}
 
 	[Message(InnerOpcode.DBQueryBatchResponse)]
-	[ProtoContract]
 	public partial class DBQueryBatchResponse: IResponse
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
 
-		[ProtoMember(91, IsRequired = true)]
 		public int Error { get; set; }
 
-		[ProtoMember(92, IsRequired = true)]
 		public string Message { get; set; }
 
-		[ProtoMember(1)]
 		public List<ComponentWithId> Components = new List<ComponentWithId>();
 
 	}
 
 	[Message(InnerOpcode.DBQueryJsonRequest)]
-	[ProtoContract]
 	public partial class DBQueryJsonRequest: IRequest
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
 
-		[ProtoMember(1, IsRequired = true)]
 		public string CollectionName;
 
-		[ProtoMember(2, IsRequired = true)]
 		public string Json;
 
 	}
 
 	[Message(InnerOpcode.DBQueryJsonResponse)]
-	[ProtoContract]
 	public partial class DBQueryJsonResponse: IResponse
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
 
-		[ProtoMember(91, IsRequired = true)]
 		public int Error { get; set; }
 
-		[ProtoMember(92, IsRequired = true)]
 		public string Message { get; set; }
 
-		[ProtoMember(1)]
 		public List<ComponentWithId> Components = new List<ComponentWithId>();
 
 	}
 
 	[Message(InnerOpcode.ObjectAddRequest)]
-	[ProtoContract]
 	public partial class ObjectAddRequest: IRequest
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
 
-		[ProtoMember(1, IsRequired = true)]
 		public long Key;
 
-		[ProtoMember(2, IsRequired = true)]
 		public long InstanceId;
 
 	}
 
 	[Message(InnerOpcode.ObjectAddResponse)]
-	[ProtoContract]
 	public partial class ObjectAddResponse: IResponse
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
 
-		[ProtoMember(91, IsRequired = true)]
 		public int Error { get; set; }
 
-		[ProtoMember(92, IsRequired = true)]
 		public string Message { get; set; }
 
 	}
 
 	[Message(InnerOpcode.ObjectRemoveRequest)]
-	[ProtoContract]
 	public partial class ObjectRemoveRequest: IRequest
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
 
-		[ProtoMember(1, IsRequired = true)]
 		public long Key;
 
 	}
 
 	[Message(InnerOpcode.ObjectRemoveResponse)]
-	[ProtoContract]
 	public partial class ObjectRemoveResponse: IResponse
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
 
-		[ProtoMember(91, IsRequired = true)]
 		public int Error { get; set; }
 
-		[ProtoMember(92, IsRequired = true)]
 		public string Message { get; set; }
 
 	}
 
 	[Message(InnerOpcode.ObjectLockRequest)]
-	[ProtoContract]
 	public partial class ObjectLockRequest: IRequest
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
 
-		[ProtoMember(1, IsRequired = true)]
 		public long Key;
 
-		[ProtoMember(2, IsRequired = true)]
 		public long InstanceId;
 
-		[ProtoMember(3, IsRequired = true)]
 		public int Time;
 
 	}
 
 	[Message(InnerOpcode.ObjectLockResponse)]
-	[ProtoContract]
 	public partial class ObjectLockResponse: IResponse
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
 
-		[ProtoMember(91, IsRequired = true)]
 		public int Error { get; set; }
 
-		[ProtoMember(92, IsRequired = true)]
 		public string Message { get; set; }
 
 	}
 
 	[Message(InnerOpcode.ObjectUnLockRequest)]
-	[ProtoContract]
 	public partial class ObjectUnLockRequest: IRequest
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
 
-		[ProtoMember(1, IsRequired = true)]
 		public long Key;
 
-		[ProtoMember(2, IsRequired = true)]
 		public long OldInstanceId;
 
-		[ProtoMember(3, IsRequired = true)]
 		public long InstanceId;
 
 	}
 
 	[Message(InnerOpcode.ObjectUnLockResponse)]
-	[ProtoContract]
 	public partial class ObjectUnLockResponse: IResponse
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
 
-		[ProtoMember(91, IsRequired = true)]
 		public int Error { get; set; }
 
-		[ProtoMember(92, IsRequired = true)]
 		public string Message { get; set; }
 
 	}
 
 	[Message(InnerOpcode.ObjectGetRequest)]
-	[ProtoContract]
 	public partial class ObjectGetRequest: IRequest
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
 
-		[ProtoMember(1, IsRequired = true)]
 		public long Key;
 
 	}
 
 	[Message(InnerOpcode.ObjectGetResponse)]
-	[ProtoContract]
 	public partial class ObjectGetResponse: IResponse
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
 
-		[ProtoMember(91, IsRequired = true)]
 		public int Error { get; set; }
 
-		[ProtoMember(92, IsRequired = true)]
 		public string Message { get; set; }
 
-		[ProtoMember(1, IsRequired = true)]
 		public long InstanceId;
 
 	}
 
 	[Message(InnerOpcode.R2G_GetLoginKey)]
-	[ProtoContract]
 	public partial class R2G_GetLoginKey: IRequest
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
 
-		[ProtoMember(1, IsRequired = true)]
 		public string Account;
 
 	}
 
 	[Message(InnerOpcode.G2R_GetLoginKey)]
-	[ProtoContract]
 	public partial class G2R_GetLoginKey: IResponse
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
 
-		[ProtoMember(91, IsRequired = true)]
 		public int Error { get; set; }
 
-		[ProtoMember(92, IsRequired = true)]
 		public string Message { get; set; }
 
-		[ProtoMember(1, IsRequired = true)]
 		public long Key;
 
 	}
 
 	[Message(InnerOpcode.G2M_CreateUnit)]
-	[ProtoContract]
 	public partial class G2M_CreateUnit: IRequest
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
 
-		[ProtoMember(1, IsRequired = true)]
 		public long PlayerId;
 
-		[ProtoMember(2, IsRequired = true)]
 		public long GateSessionId;
 
 	}
 
 	[Message(InnerOpcode.M2G_CreateUnit)]
-	[ProtoContract]
 	public partial class M2G_CreateUnit: IResponse
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
 
-		[ProtoMember(91, IsRequired = true)]
 		public int Error { get; set; }
 
-		[ProtoMember(92, IsRequired = true)]
 		public string Message { get; set; }
 
-		[ProtoMember(1, IsRequired = true)]
 		public long UnitId;
 
-		[ProtoMember(2, IsRequired = true)]
 		public int Count;
 
 	}
 
 	[Message(InnerOpcode.G2M_SessionDisconnect)]
-	[ProtoContract]
 	public partial class G2M_SessionDisconnect: IActorMessage
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
 
-		[ProtoMember(93, IsRequired = true)]
 		public long ActorId { get; set; }
 
 	}

+ 3 - 0
Server/Hotfix/Module/Message/InnerOpcode.cs

@@ -1,3 +1,6 @@
+using ETModel;
+using System.Collections.Generic;
+using MongoDB.Bson.Serialization.Attributes;
 namespace ETHotfix
 {
 	public static partial class InnerOpcode

+ 2 - 2
Server/Hotfix/Module/Message/NetOuterComponentSystem.cs

@@ -8,7 +8,7 @@ namespace ETHotfix
 	{
 		public override void Awake(NetOuterComponent self)
 		{
-			self.Awake(NetworkProtocol.KCP);
+			self.Awake(NetworkProtocol.TCP);
 			self.MessagePacker = new ProtobufPacker();
 			self.MessageDispatcher = new OuterMessageDispatcher();
 		}
@@ -19,7 +19,7 @@ namespace ETHotfix
 	{
 		public override void Awake(NetOuterComponent self, IPEndPoint ipEndPoint)
 		{
-			self.Awake(NetworkProtocol.KCP, ipEndPoint);
+			self.Awake(NetworkProtocol.TCP, ipEndPoint);
 			self.MessagePacker = new ProtobufPacker();
 			self.MessageDispatcher = new OuterMessageDispatcher();
 		}

+ 0 - 219
Server/Hotfix/Module/Message/OuterMessage.cs

@@ -1,219 +0,0 @@
-using ProtoBuf;
-using ETModel;
-using System.Collections.Generic;
-using MongoDB.Bson.Serialization.Attributes;
-namespace ETHotfix
-{
-	[Message(OuterOpcode.Actor_Test)]
-	[ProtoContract]
-	public partial class Actor_Test: IActorMessage
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-		[ProtoMember(93, IsRequired = true)]
-		public long ActorId { get; set; }
-
-		[ProtoMember(1, IsRequired = true)]
-		public string Info;
-
-	}
-
-	[Message(OuterOpcode.Actor_TestRequest)]
-	[ProtoContract]
-	public partial class Actor_TestRequest: IActorRequest
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-		[ProtoMember(93, IsRequired = true)]
-		public long ActorId { get; set; }
-
-		[ProtoMember(1, IsRequired = true)]
-		public string request;
-
-	}
-
-	[Message(OuterOpcode.Actor_TestResponse)]
-	[ProtoContract]
-	public partial class Actor_TestResponse: IActorResponse
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-		[ProtoMember(91, IsRequired = true)]
-		public int Error { get; set; }
-
-		[ProtoMember(92, IsRequired = true)]
-		public string Message { get; set; }
-
-		[ProtoMember(1, IsRequired = true)]
-		public string response;
-
-	}
-
-	[Message(OuterOpcode.Actor_TransferRequest)]
-	[ProtoContract]
-	public partial class Actor_TransferRequest: IActorRequest
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-		[ProtoMember(93, IsRequired = true)]
-		public long ActorId { get; set; }
-
-		[ProtoMember(1, IsRequired = true)]
-		public int MapIndex;
-
-	}
-
-	[Message(OuterOpcode.Actor_TransferResponse)]
-	[ProtoContract]
-	public partial class Actor_TransferResponse: IActorResponse
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-		[ProtoMember(91, IsRequired = true)]
-		public int Error { get; set; }
-
-		[ProtoMember(92, IsRequired = true)]
-		public string Message { get; set; }
-
-	}
-
-	[Message(OuterOpcode.C2G_EnterMap)]
-	[ProtoContract]
-	public partial class C2G_EnterMap: IRequest
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-	}
-
-	[Message(OuterOpcode.G2C_EnterMap)]
-	[ProtoContract]
-	public partial class G2C_EnterMap: IResponse
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-		[ProtoMember(91, IsRequired = true)]
-		public int Error { get; set; }
-
-		[ProtoMember(92, IsRequired = true)]
-		public string Message { get; set; }
-
-		[ProtoMember(1, IsRequired = true)]
-		public long UnitId;
-
-		[ProtoMember(2, IsRequired = true)]
-		public int Count;
-
-	}
-
-	[Message(OuterOpcode.UnitInfo)]
-	[ProtoContract]
-	public partial class UnitInfo
-	{
-		[ProtoMember(1, IsRequired = true)]
-		public long UnitId;
-
-		[ProtoMember(2, IsRequired = true)]
-		public int X;
-
-		[ProtoMember(3, IsRequired = true)]
-		public int Z;
-
-	}
-
-	[Message(OuterOpcode.Actor_CreateUnits)]
-	[ProtoContract]
-	public partial class Actor_CreateUnits: IActorMessage
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-		[ProtoMember(93, IsRequired = true)]
-		public long ActorId { get; set; }
-
-		[ProtoMember(1)]
-		public List<UnitInfo> Units = new List<UnitInfo>();
-
-	}
-
-	[Message(OuterOpcode.Frame_ClickMap)]
-	[ProtoContract]
-	public partial class Frame_ClickMap: IFrameMessage
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-		[ProtoMember(94, IsRequired = true)]
-		public long Id { get; set; }
-
-		[ProtoMember(1, IsRequired = true)]
-		public int X;
-
-		[ProtoMember(2, IsRequired = true)]
-		public int Z;
-
-	}
-
-	[Message(OuterOpcode.C2M_Reload)]
-	[ProtoContract]
-	public partial class C2M_Reload: IRequest
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-		[ProtoMember(1, IsRequired = true)]
-		public AppType AppType;
-
-	}
-
-	[Message(OuterOpcode.M2C_Reload)]
-	[ProtoContract]
-	public partial class M2C_Reload: IResponse
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-		[ProtoMember(91, IsRequired = true)]
-		public int Error { get; set; }
-
-		[ProtoMember(92, IsRequired = true)]
-		public string Message { get; set; }
-
-	}
-
-	[Message(OuterOpcode.C2R_Ping)]
-	[ProtoContract]
-	public partial class C2R_Ping: IRequest
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-	}
-
-	[Message(OuterOpcode.R2C_Ping)]
-	[ProtoContract]
-	public partial class R2C_Ping: IResponse
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-		[ProtoMember(91, IsRequired = true)]
-		public int Error { get; set; }
-
-		[ProtoMember(92, IsRequired = true)]
-		public string Message { get; set; }
-
-	}
-	
-	[Message(OuterOpcode.G2C_Test)]
-	[ProtoContract]
-	public partial class G2C_Test: IMessage
-	{
-	}
-}

+ 3 - 2
Server/Hotfix/Module/Message/OuterMessageDispatcher.cs

@@ -1,5 +1,6 @@
 using System;
 using ETModel;
+using Google.Protobuf;
 
 namespace ETHotfix
 {
@@ -34,11 +35,11 @@ namespace ETHotfix
 	
 					// 这里设置了帧消息的id,防止客户端伪造
 					iFrameMessage.Id = unitId;
-	
+
 					OneFrameMessage oneFrameMessage = new OneFrameMessage
 					{
 						Op = packet.Opcode,
-						AMessage = session.Network.MessagePacker.SerializeToByteArray(iFrameMessage)
+						AMessage = ByteString.CopyFrom(session.Network.MessagePacker.SerializeToByteArray(iFrameMessage))
 					};
 					actorMessageSender.Send(oneFrameMessage);
 					return;

+ 0 - 21
Server/Hotfix/Module/Message/OuterOpcode.cs

@@ -1,21 +0,0 @@
-namespace ETHotfix
-{
-	public static partial class OuterOpcode
-	{
-		 public const ushort Actor_Test = 101;
-		 public const ushort Actor_TestRequest = 102;
-		 public const ushort Actor_TestResponse = 103;
-		 public const ushort Actor_TransferRequest = 104;
-		 public const ushort Actor_TransferResponse = 105;
-		 public const ushort C2G_EnterMap = 106;
-		 public const ushort G2C_EnterMap = 107;
-		 public const ushort UnitInfo = 108;
-		 public const ushort Actor_CreateUnits = 109;
-		 public const ushort Frame_ClickMap = 110;
-		 public const ushort C2M_Reload = 111;
-		 public const ushort M2C_Reload = 112;
-		 public const ushort C2R_Ping = 113;
-		 public const ushort R2C_Ping = 114;
-		 public const ushort G2C_Test = 115;
-	}
-}

+ 6 - 0
Server/Hotfix/Server.Hotfix.csproj

@@ -20,6 +20,12 @@
     <EmbeddedResource Remove="Other\**" />
     <None Remove="Other\**" />
   </ItemGroup>
+  <ItemGroup>
+    <Compile Include="..\..\Unity\Assets\Scripts\Module\Message\OuterMessage.cs" Link="Module\Message\OuterMessage.cs" />
+    <Compile Include="..\..\Unity\Assets\Scripts\Module\Message\OuterOpcode.cs" Link="Module\Message\OuterOpcode.cs" />
+    <Compile Include="..\..\Unity\Hotfix\Module\Message\HotfixMessage.cs" Link="Module\Message\HotfixMessage.cs" />
+    <Compile Include="..\..\Unity\Hotfix\Module\Message\HotfixOpcode.cs" Link="Module\Message\HotfixOpcode.cs" />
+  </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\Model\Server.Model.csproj" />
   </ItemGroup>

+ 1 - 9
Server/Model/Module/Actor/ActorResponse.cs

@@ -1,23 +1,15 @@
-using System;
-using System.Collections.Generic;
-using ProtoBuf;
-
-namespace ETModel
+namespace ETModel
 {
 	/// <summary>
 	/// actor RPC消息响应
 	/// </summary>
 	[Message(Opcode.ActorResponse)]
-	[ProtoContract]
 	public class ActorResponse : IActorResponse
 	{
-		[ProtoMember(90, IsRequired = true)]
 		public int RpcId { get; set; }
 
-		[ProtoMember(91, IsRequired = true)]
 		public int Error { get; set; }
 
-		[ProtoMember(92, IsRequired = true)]
 		public string Message { get; set; }
 	}
 }

+ 2 - 32
Server/Model/Module/Message/MongoPacker.cs

@@ -10,44 +10,14 @@ namespace ETModel
 			return MongoHelper.ToBson(obj);
 		}
 
-		public string SerializeToText(object obj)
-		{
-			return MongoHelper.ToJson(obj);
-		}
-
-		public object DeserializeFrom(Type type, byte[] bytes)
-		{
-			return MongoHelper.FromBson(type, bytes);
-		}
-
-		public object DeserializeFrom(Type type, Stream stream)
-		{
-			return MongoHelper.FromStream(type, stream);
-		}
-
 		public object DeserializeFrom(Type type, byte[] bytes, int index, int count)
 		{
 			return MongoHelper.FromBson(type, bytes, index, count);
 		}
 
-		public T DeserializeFrom<T>(byte[] bytes)
+		public object DeserializeFrom(Type type, MemoryStream stream)
 		{
-			return MongoHelper.FromBson<T>(bytes);
-		}
-
-		public T DeserializeFrom<T>(byte[] bytes, int index, int count)
-		{
-			return MongoHelper.FromBson<T>(bytes, index, count);
-		}
-
-		public T DeserializeFrom<T>(string str)
-		{
-			return MongoHelper.FromJson<T>(str);
-		}
-
-		public object DeserializeFrom(Type type, string str)
-		{
-			return MongoHelper.FromJson(type, str);
+			return MongoHelper.FromStream(type, stream);
 		}
 	}
 }

+ 3 - 2
Server/Model/Server.Model.csproj

@@ -29,7 +29,6 @@
     <Compile Include="..\..\Unity\Assets\Scripts\Base\Helper\MethodInfoHelper.cs" Link="Base\Helper\MethodInfoHelper.cs" />
     <Compile Include="..\..\Unity\Assets\Scripts\Base\Helper\NetHelper.cs" Link="Base\Helper\NetHelper.cs" />
     <Compile Include="..\..\Unity\Assets\Scripts\Base\Helper\ObjectHelper.cs" Link="Base\Helper\ObjectHelper.cs" />
-    <Compile Include="..\..\Unity\Assets\Scripts\Base\Helper\ProtobufHelper.cs" Link="Base\Helper\ProtobufHelper.cs" />
     <Compile Include="..\..\Unity\Assets\Scripts\Base\Helper\RandomHelper.cs" Link="Base\Helper\RandomHelper.cs" />
     <Compile Include="..\..\Unity\Assets\Scripts\Base\Helper\StringHelper.cs" Link="Base\Helper\StringHelper.cs" />
     <Compile Include="..\..\Unity\Assets\Scripts\Base\Helper\TimeHelper.cs" Link="Base\Helper\TimeHelper.cs" />
@@ -70,6 +69,7 @@
     <Compile Include="..\..\Unity\Assets\Scripts\Module\Config\ConfigComponent.cs" Link="Module\Config\ConfigComponent.cs" />
     <Compile Include="..\..\Unity\Assets\Scripts\Module\Config\IConfig.cs" Link="Module\Config\IConfig.cs" />
     <Compile Include="..\..\Unity\Assets\Scripts\Module\FrameSync\FrameMessage.cs" Link="Module\FrameSync\FrameMessage.cs" />
+    <Compile Include="..\..\Unity\Assets\Scripts\Module\FrameSync\FrameProto.cs" Link="Module\FrameSync\FrameProto.cs" />
     <Compile Include="..\..\Unity\Assets\Scripts\Module\Message\AMHandler.cs" Link="Module\Message\AMHandler.cs" />
     <Compile Include="..\..\Unity\Assets\Scripts\Module\Message\ErrorCode.cs" Link="Module\Message\ErrorCode.cs" />
     <Compile Include="..\..\Unity\Assets\Scripts\Module\Message\IActorMessage.cs" Link="Module\Message\IActorMessage.cs" />
@@ -94,6 +94,7 @@
     <Compile Include="..\..\Unity\Assets\Scripts\Module\Message\Opcode.cs" Link="Module\Message\Opcode.cs" />
     <Compile Include="..\..\Unity\Assets\Scripts\Module\Message\OpcodeHelper.cs" Link="Module\Message\OpcodeHelper.cs" />
     <Compile Include="..\..\Unity\Assets\Scripts\Module\Message\OpcodeTypeComponent.cs" Link="Module\Message\OpcodeTypeComponent.cs" />
+    <Compile Include="..\..\Unity\Assets\Scripts\Module\Message\ProtobufHelper.cs" Link="Module\Message\ProtobufHelper.cs" />
     <Compile Include="..\..\Unity\Assets\Scripts\Module\Message\ProtobufPacker.cs" Link="Module\Message\ProtobufPacker.cs" />
     <Compile Include="..\..\Unity\Assets\Scripts\Module\Message\RpcException.cs" Link="Module\Message\RpcException.cs" />
     <Compile Include="..\..\Unity\Assets\Scripts\Module\Message\Session.cs" Link="Module\Message\Session.cs" />
@@ -108,10 +109,10 @@
   <ItemGroup>
     <PackageReference Include="CommandLineParser" Version="2.2.1" />
     <PackageReference Include="NLog" Version="4.5.4" />
-    <PackageReference Include="protobuf-net" Version="2.3.8-alpha1" />
     <PackageReference Include="SharpZipLib" Version="1.0.0-alpha2" />
   </ItemGroup>
   <ItemGroup>
+    <ProjectReference Include="..\ThirdParty\Google.Protobuf\Google.Protobuf.csproj" />
     <ProjectReference Include="..\ThirdParty\MongodbDriver\DotNetCoreDriver\MongoDB.Bson\MongoDB.Bson.csproj" />
     <ProjectReference Include="..\ThirdParty\MongodbDriver\DotNetCoreDriver\MongoDB.Driver.Core\MongoDB.Driver.Core.csproj" />
     <ProjectReference Include="..\ThirdParty\MongodbDriver\DotNetCoreDriver\MongoDB.Driver\MongoDB.Driver.csproj" />

+ 79 - 0
Server/ThirdParty/Google.Protobuf/ByteArray.cs

@@ -0,0 +1,79 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Provides a utility routine to copy small arrays much more quickly than Buffer.BlockCopy
+    /// </summary>
+    internal static class ByteArray
+    {
+        /// <summary>
+        /// The threshold above which you should use Buffer.BlockCopy rather than ByteArray.Copy
+        /// </summary>
+        private const int CopyThreshold = 12;
+
+        /// <summary>
+        /// Determines which copy routine to use based on the number of bytes to be copied.
+        /// </summary>
+        internal static void Copy(byte[] src, int srcOffset, byte[] dst, int dstOffset, int count)
+        {
+            if (count > CopyThreshold)
+            {
+                Buffer.BlockCopy(src, srcOffset, dst, dstOffset, count);
+            }
+            else
+            {
+                int stop = srcOffset + count;
+                for (int i = srcOffset; i < stop; i++)
+                {
+                    dst[dstOffset++] = src[i];
+                }
+            }
+        }
+
+        /// <summary>
+        /// Reverses the order of bytes in the array
+        /// </summary>
+        internal static void Reverse(byte[] bytes)
+        {
+            for (int first = 0, last = bytes.Length - 1; first < last; first++, last--)
+            {
+                byte temp = bytes[first];
+                bytes[first] = bytes[last];
+                bytes[last] = temp;
+            }
+        }
+    }
+}

+ 378 - 0
Server/ThirdParty/Google.Protobuf/ByteString.cs

@@ -0,0 +1,378 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using Google.Protobuf.Compatibility;
+using MongoDB.Bson.Serialization.Attributes;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Immutable array of bytes.
+    /// </summary>
+    public sealed class ByteString : IEnumerable<byte>, IEquatable<ByteString>
+    {
+        private static readonly ByteString empty = new ByteString(new byte[0]);
+
+        public byte[] bytes;
+
+        /// <summary>
+        /// Unsafe operations that can cause IO Failure and/or other catestrophic side-effects.
+        /// </summary>
+        internal static class Unsafe
+        {
+            /// <summary>
+            /// Constructs a new ByteString from the given byte array. The array is
+            /// *not* copied, and must not be modified after this constructor is called.
+            /// </summary>
+            internal static ByteString FromBytes(byte[] bytes)
+            {
+                return new ByteString(bytes);
+            }
+
+            /// <summary>
+            /// Provides direct, unrestricted access to the bytes contained in this instance.
+            /// You must not modify or resize the byte array returned by this method.
+            /// </summary>
+            internal static byte[] GetBuffer(ByteString bytes)
+            {
+                return bytes.bytes;
+            }
+        }
+
+        /// <summary>
+        /// Internal use only.  Ensure that the provided array is not mutated and belongs to this instance.
+        /// </summary>
+        internal static ByteString AttachBytes(byte[] bytes)
+        {
+            return new ByteString(bytes);
+        }
+        
+        public ByteString()
+        {}
+
+        public ByteString(List<byte> list)
+        {
+            this.bytes = list.ToArray();
+        }
+        /// <summary>
+        /// Constructs a new ByteString from the given byte array. The array is
+        /// *not* copied, and must not be modified after this constructor is called.
+        /// </summary>
+        public ByteString(byte[] bytes)
+        {
+            this.bytes = bytes;
+        }
+
+        /// <summary>
+        /// Returns an empty ByteString.
+        /// </summary>
+        public static ByteString Empty
+        {
+            get { return empty; }
+        }
+
+        /// <summary>
+        /// Returns the length of this ByteString in bytes.
+        /// </summary>
+        [BsonIgnore]
+        public int Length
+        {
+            get { return bytes.Length; }
+        }
+
+        /// <summary>
+        /// Returns <c>true</c> if this byte string is empty, <c>false</c> otherwise.
+        /// </summary>
+        [BsonIgnore]
+        public bool IsEmpty
+        {
+            get { return Length == 0; }
+        }
+
+        /// <summary>
+        /// Converts this <see cref="ByteString"/> into a byte array.
+        /// </summary>
+        /// <remarks>The data is copied - changes to the returned array will not be reflected in this <c>ByteString</c>.</remarks>
+        /// <returns>A byte array with the same data as this <c>ByteString</c>.</returns>
+        public byte[] ToByteArray()
+        {
+            return (byte[]) bytes.Clone();
+        }
+
+        /// <summary>
+        /// Converts this <see cref="ByteString"/> into a standard base64 representation.
+        /// </summary>
+        /// <returns>A base64 representation of this <c>ByteString</c>.</returns>
+        public string ToBase64()
+        {
+            return Convert.ToBase64String(bytes);
+        }
+
+        /// <summary>
+        /// Constructs a <see cref="ByteString" /> from the Base64 Encoded String.
+        /// </summary>
+        public static ByteString FromBase64(string bytes)
+        {
+            // By handling the empty string explicitly, we not only optimize but we fix a
+            // problem on CF 2.0. See issue 61 for details.
+            return bytes == "" ? Empty : new ByteString(Convert.FromBase64String(bytes));
+        }
+
+        /// <summary>
+        /// Constructs a <see cref="ByteString"/> from data in the given stream, synchronously.
+        /// </summary>
+        /// <remarks>If successful, <paramref name="stream"/> will be read completely, from the position
+        /// at the start of the call.</remarks>
+        /// <param name="stream">The stream to copy into a ByteString.</param>
+        /// <returns>A ByteString with content read from the given stream.</returns>
+        public static ByteString FromStream(Stream stream)
+        {
+            ProtoPreconditions.CheckNotNull(stream, "stream");
+            int capacity = stream.CanSeek ? checked((int) (stream.Length - stream.Position)) : 0;
+            var memoryStream = new MemoryStream(capacity);
+            stream.CopyTo(memoryStream);
+
+            // Avoid an extra copy if we can.
+            byte[] bytes = memoryStream.Length == memoryStream.Capacity ? memoryStream.GetBuffer() : memoryStream.ToArray();
+
+            return AttachBytes(bytes);
+        }
+
+        /// <summary>
+        /// Constructs a <see cref="ByteString" /> from the given array. The contents
+        /// are copied, so further modifications to the array will not
+        /// be reflected in the returned ByteString.
+        /// This method can also be invoked in <c>ByteString.CopyFrom(0xaa, 0xbb, ...)</c> form
+        /// which is primarily useful for testing.
+        /// </summary>
+        public static ByteString CopyFrom(params byte[] bytes)
+        {
+            return new ByteString((byte[]) bytes.Clone());
+        }
+
+        /// <summary>
+        /// Constructs a <see cref="ByteString" /> from a portion of a byte array.
+        /// </summary>
+        public static ByteString CopyFrom(byte[] bytes, int offset, int count)
+        {
+            byte[] portion = new byte[count];
+            ByteArray.Copy(bytes, offset, portion, 0, count);
+            return new ByteString(portion);
+        }
+
+        /// <summary>
+        /// Creates a new <see cref="ByteString" /> by encoding the specified text with
+        /// the given encoding.
+        /// </summary>
+        public static ByteString CopyFrom(string text, Encoding encoding)
+        {
+            return new ByteString(encoding.GetBytes(text));
+        }
+
+        /// <summary>
+        /// Creates a new <see cref="ByteString" /> by encoding the specified text in UTF-8.
+        /// </summary>
+        public static ByteString CopyFromUtf8(string text)
+        {
+            return CopyFrom(text, Encoding.UTF8);
+        }
+
+        /// <summary>
+        /// Retuns the byte at the given index.
+        /// </summary>
+        [BsonIgnore]
+        public byte this[int index]
+        {
+            get { return bytes[index]; }
+        }
+
+        /// <summary>
+        /// Converts this <see cref="ByteString"/> into a string by applying the given encoding.
+        /// </summary>
+        /// <remarks>
+        /// This method should only be used to convert binary data which was the result of encoding
+        /// text with the given encoding.
+        /// </remarks>
+        /// <param name="encoding">The encoding to use to decode the binary data into text.</param>
+        /// <returns>The result of decoding the binary data with the given decoding.</returns>
+        public string ToString(Encoding encoding)
+        {
+            return encoding.GetString(bytes, 0, bytes.Length);
+        }
+
+        /// <summary>
+        /// Converts this <see cref="ByteString"/> into a string by applying the UTF-8 encoding.
+        /// </summary>
+        /// <remarks>
+        /// This method should only be used to convert binary data which was the result of encoding
+        /// text with UTF-8.
+        /// </remarks>
+        /// <returns>The result of decoding the binary data with the given decoding.</returns>
+        public string ToStringUtf8()
+        {
+            return ToString(Encoding.UTF8);
+        }
+
+        /// <summary>
+        /// Returns an iterator over the bytes in this <see cref="ByteString"/>.
+        /// </summary>
+        /// <returns>An iterator over the bytes in this object.</returns>
+        public IEnumerator<byte> GetEnumerator()
+        {
+            return ((IEnumerable<byte>) bytes).GetEnumerator();
+        }
+
+        /// <summary>
+        /// Returns an iterator over the bytes in this <see cref="ByteString"/>.
+        /// </summary>
+        /// <returns>An iterator over the bytes in this object.</returns>
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return GetEnumerator();
+        }
+
+        /// <summary>
+        /// Creates a CodedInputStream from this ByteString's data.
+        /// </summary>
+        public CodedInputStream CreateCodedInput()
+        {
+            // We trust CodedInputStream not to reveal the provided byte array or modify it
+            return new CodedInputStream(bytes);
+        }
+
+        /// <summary>
+        /// Compares two byte strings for equality.
+        /// </summary>
+        /// <param name="lhs">The first byte string to compare.</param>
+        /// <param name="rhs">The second byte string to compare.</param>
+        /// <returns><c>true</c> if the byte strings are equal; false otherwise.</returns>
+        public static bool operator ==(ByteString lhs, ByteString rhs)
+        {
+            if (ReferenceEquals(lhs, rhs))
+            {
+                return true;
+            }
+            if (ReferenceEquals(lhs, null) || ReferenceEquals(rhs, null))
+            {
+                return false;
+            }
+            if (lhs.bytes.Length != rhs.bytes.Length)
+            {
+                return false;
+            }
+            for (int i = 0; i < lhs.Length; i++)
+            {
+                if (rhs.bytes[i] != lhs.bytes[i])
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        /// <summary>
+        /// Compares two byte strings for inequality.
+        /// </summary>
+        /// <param name="lhs">The first byte string to compare.</param>
+        /// <param name="rhs">The second byte string to compare.</param>
+        /// <returns><c>false</c> if the byte strings are equal; true otherwise.</returns>
+        public static bool operator !=(ByteString lhs, ByteString rhs)
+        {
+            return !(lhs == rhs);
+        }
+
+        /// <summary>
+        /// Compares this byte string with another object.
+        /// </summary>
+        /// <param name="obj">The object to compare this with.</param>
+        /// <returns><c>true</c> if <paramref name="obj"/> refers to an equal <see cref="ByteString"/>; <c>false</c> otherwise.</returns>
+        public override bool Equals(object obj)
+        {
+            return this == (obj as ByteString);
+        }
+
+        /// <summary>
+        /// Returns a hash code for this object. Two equal byte strings
+        /// will return the same hash code.
+        /// </summary>
+        /// <returns>A hash code for this object.</returns>
+        public override int GetHashCode()
+        {
+            int ret = 23;
+            foreach (byte b in bytes)
+            {
+                ret = (ret * 31) + b;
+            }
+            return ret;
+        }
+
+        /// <summary>
+        /// Compares this byte string with another.
+        /// </summary>
+        /// <param name="other">The <see cref="ByteString"/> to compare this with.</param>
+        /// <returns><c>true</c> if <paramref name="other"/> refers to an equal byte string; <c>false</c> otherwise.</returns>
+        public bool Equals(ByteString other)
+        {
+            return this == other;
+        }
+
+        /// <summary>
+        /// Used internally by CodedOutputStream to avoid creating a copy for the write
+        /// </summary>
+        internal void WriteRawBytesTo(CodedOutputStream outputStream)
+        {
+            outputStream.WriteRawBytes(bytes, 0, bytes.Length);
+        }
+
+        /// <summary>
+        /// Copies the entire byte array to the destination array provided at the offset specified.
+        /// </summary>
+        public void CopyTo(byte[] array, int position)
+        {
+            ByteArray.Copy(bytes, 0, array, position, bytes.Length);
+        }
+
+        /// <summary>
+        /// Writes the entire byte array to the provided stream
+        /// </summary>
+        public void WriteTo(Stream outputStream)
+        {
+            outputStream.Write(bytes, 0, bytes.Length);
+        }
+    }
+}

+ 1274 - 0
Server/ThirdParty/Google.Protobuf/CodedInputStream.cs

@@ -0,0 +1,1274 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using Google.Protobuf.Collections;
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Reads and decodes protocol message fields.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// This class is generally used by generated code to read appropriate
+    /// primitives from the stream. It effectively encapsulates the lowest
+    /// levels of protocol buffer format.
+    /// </para>
+    /// <para>
+    /// Repeated fields and map fields are not handled by this class; use <see cref="RepeatedField{T}"/>
+    /// and <see cref="MapField{TKey, TValue}"/> to serialize such fields.
+    /// </para>
+    /// </remarks>
+    public sealed class CodedInputStream : IDisposable
+    {
+        /// <summary>
+        /// Whether to leave the underlying stream open when disposing of this stream.
+        /// This is always true when there's no stream.
+        /// </summary>
+        private readonly bool leaveOpen;
+
+        /// <summary>
+        /// Buffer of data read from the stream or provided at construction time.
+        /// </summary>
+        private readonly byte[] buffer;
+
+        /// <summary>
+        /// The index of the buffer at which we need to refill from the stream (if there is one).
+        /// </summary>
+        private int bufferSize;
+
+        private int bufferSizeAfterLimit = 0;
+        /// <summary>
+        /// The position within the current buffer (i.e. the next byte to read)
+        /// </summary>
+        private int bufferPos = 0;
+
+        /// <summary>
+        /// The stream to read further input from, or null if the byte array buffer was provided
+        /// directly on construction, with no further data available.
+        /// </summary>
+        private readonly Stream input;
+
+        /// <summary>
+        /// The last tag we read. 0 indicates we've read to the end of the stream
+        /// (or haven't read anything yet).
+        /// </summary>
+        private uint lastTag = 0;
+
+        /// <summary>
+        /// The next tag, used to store the value read by PeekTag.
+        /// </summary>
+        private uint nextTag = 0;
+        private bool hasNextTag = false;
+
+        internal const int DefaultRecursionLimit = 64;
+        internal const int DefaultSizeLimit = 64 << 20; // 64MB
+        internal const int BufferSize = 4096;
+
+        /// <summary>
+        /// The total number of bytes read before the current buffer. The
+        /// total bytes read up to the current position can be computed as
+        /// totalBytesRetired + bufferPos.
+        /// </summary>
+        private int totalBytesRetired = 0;
+
+        /// <summary>
+        /// The absolute position of the end of the current message.
+        /// </summary> 
+        private int currentLimit = int.MaxValue;
+
+        private int recursionDepth = 0;
+
+        private readonly int recursionLimit;
+        private readonly int sizeLimit;
+
+        #region Construction
+        // Note that the checks are performed such that we don't end up checking obviously-valid things
+        // like non-null references for arrays we've just created.
+
+        /// <summary>
+        /// Creates a new CodedInputStream reading data from the given byte array.
+        /// </summary>
+        public CodedInputStream(byte[] buffer) : this(null, ProtoPreconditions.CheckNotNull(buffer, "buffer"), 0, buffer.Length, true)
+        {            
+        }
+
+        /// <summary>
+        /// Creates a new <see cref="CodedInputStream"/> that reads from the given byte array slice.
+        /// </summary>
+        public CodedInputStream(byte[] buffer, int offset, int length)
+            : this(null, ProtoPreconditions.CheckNotNull(buffer, "buffer"), offset, offset + length, true)
+        {            
+            if (offset < 0 || offset > buffer.Length)
+            {
+                throw new ArgumentOutOfRangeException("offset", "Offset must be within the buffer");
+            }
+            if (length < 0 || offset + length > buffer.Length)
+            {
+                throw new ArgumentOutOfRangeException("length", "Length must be non-negative and within the buffer");
+            }
+        }
+
+        /// <summary>
+        /// Creates a new <see cref="CodedInputStream"/> reading data from the given stream, which will be disposed
+        /// when the returned object is disposed.
+        /// </summary>
+        /// <param name="input">The stream to read from.</param>
+        public CodedInputStream(Stream input) : this(input, false)
+        {
+        }
+
+        /// <summary>
+        /// Creates a new <see cref="CodedInputStream"/> reading data from the given stream.
+        /// </summary>
+        /// <param name="input">The stream to read from.</param>
+        /// <param name="leaveOpen"><c>true</c> to leave <paramref name="input"/> open when the returned
+        /// <c cref="CodedInputStream"/> is disposed; <c>false</c> to dispose of the given stream when the
+        /// returned object is disposed.</param>
+        public CodedInputStream(Stream input, bool leaveOpen)
+            : this(ProtoPreconditions.CheckNotNull(input, "input"), new byte[BufferSize], 0, 0, leaveOpen)
+        {
+        }
+        
+        /// <summary>
+        /// Creates a new CodedInputStream reading data from the given
+        /// stream and buffer, using the default limits.
+        /// </summary>
+        internal CodedInputStream(Stream input, byte[] buffer, int bufferPos, int bufferSize, bool leaveOpen)
+        {
+            this.input = input;
+            this.buffer = buffer;
+            this.bufferPos = bufferPos;
+            this.bufferSize = bufferSize;
+            this.sizeLimit = DefaultSizeLimit;
+            this.recursionLimit = DefaultRecursionLimit;
+            this.leaveOpen = leaveOpen;
+        }
+
+        /// <summary>
+        /// Creates a new CodedInputStream reading data from the given
+        /// stream and buffer, using the specified limits.
+        /// </summary>
+        /// <remarks>
+        /// This chains to the version with the default limits instead of vice versa to avoid
+        /// having to check that the default values are valid every time.
+        /// </remarks>
+        internal CodedInputStream(Stream input, byte[] buffer, int bufferPos, int bufferSize, int sizeLimit, int recursionLimit, bool leaveOpen)
+            : this(input, buffer, bufferPos, bufferSize, leaveOpen)
+        {
+            if (sizeLimit <= 0)
+            {
+                throw new ArgumentOutOfRangeException("sizeLimit", "Size limit must be positive");
+            }
+            if (recursionLimit <= 0)
+            {
+                throw new ArgumentOutOfRangeException("recursionLimit!", "Recursion limit must be positive");
+            }
+            this.sizeLimit = sizeLimit;
+            this.recursionLimit = recursionLimit;
+        }
+        #endregion
+
+        /// <summary>
+        /// Creates a <see cref="CodedInputStream"/> with the specified size and recursion limits, reading
+        /// from an input stream.
+        /// </summary>
+        /// <remarks>
+        /// This method exists separately from the constructor to reduce the number of constructor overloads.
+        /// It is likely to be used considerably less frequently than the constructors, as the default limits
+        /// are suitable for most use cases.
+        /// </remarks>
+        /// <param name="input">The input stream to read from</param>
+        /// <param name="sizeLimit">The total limit of data to read from the stream.</param>
+        /// <param name="recursionLimit">The maximum recursion depth to allow while reading.</param>
+        /// <returns>A <c>CodedInputStream</c> reading from <paramref name="input"/> with the specified size
+        /// and recursion limits.</returns>
+        public static CodedInputStream CreateWithLimits(Stream input, int sizeLimit, int recursionLimit)
+        {
+            // Note: we may want an overload accepting leaveOpen
+            return new CodedInputStream(input, new byte[BufferSize], 0, 0, sizeLimit, recursionLimit, false);
+        }
+
+        /// <summary>
+        /// Returns the current position in the input stream, or the position in the input buffer
+        /// </summary>
+        public long Position 
+        {
+            get
+            {
+                if (input != null)
+                {
+                    return input.Position - ((bufferSize + bufferSizeAfterLimit) - bufferPos);
+                }
+                return bufferPos;
+            }
+        }
+
+        /// <summary>
+        /// Returns the last tag read, or 0 if no tags have been read or we've read beyond
+        /// the end of the stream.
+        /// </summary>
+        internal uint LastTag { get { return lastTag; } }
+
+        /// <summary>
+        /// Returns the size limit for this stream.
+        /// </summary>
+        /// <remarks>
+        /// This limit is applied when reading from the underlying stream, as a sanity check. It is
+        /// not applied when reading from a byte array data source without an underlying stream.
+        /// The default value is 64MB.
+        /// </remarks>
+        /// <value>
+        /// The size limit.
+        /// </value>
+        public int SizeLimit { get { return sizeLimit; } }
+
+        /// <summary>
+        /// Returns the recursion limit for this stream. This limit is applied whilst reading messages,
+        /// to avoid maliciously-recursive data.
+        /// </summary>
+        /// <remarks>
+        /// The default limit is 64.
+        /// </remarks>
+        /// <value>
+        /// The recursion limit for this stream.
+        /// </value>
+        public int RecursionLimit { get { return recursionLimit; } }
+
+        /// <summary>
+        /// Disposes of this instance, potentially closing any underlying stream.
+        /// </summary>
+        /// <remarks>
+        /// As there is no flushing to perform here, disposing of a <see cref="CodedInputStream"/> which
+        /// was constructed with the <c>leaveOpen</c> option parameter set to <c>true</c> (or one which
+        /// was constructed to read from a byte array) has no effect.
+        /// </remarks>
+        public void Dispose()
+        {
+            if (!leaveOpen)
+            {
+                input.Dispose();
+            }
+        }
+
+        #region Validation
+        /// <summary>
+        /// Verifies that the last call to ReadTag() returned tag 0 - in other words,
+        /// we've reached the end of the stream when we expected to.
+        /// </summary>
+        /// <exception cref="InvalidProtocolBufferException">The 
+        /// tag read was not the one specified</exception>
+        internal void CheckReadEndOfStreamTag()
+        {
+            if (lastTag != 0)
+            {
+                throw InvalidProtocolBufferException.MoreDataAvailable();
+            }
+        }
+        #endregion
+
+        #region Reading of tags etc
+
+        /// <summary>
+        /// Peeks at the next field tag. This is like calling <see cref="ReadTag"/>, but the
+        /// tag is not consumed. (So a subsequent call to <see cref="ReadTag"/> will return the
+        /// same value.)
+        /// </summary>
+        public uint PeekTag()
+        {
+            if (hasNextTag)
+            {
+                return nextTag;
+            }
+
+            uint savedLast = lastTag;
+            nextTag = ReadTag();
+            hasNextTag = true;
+            lastTag = savedLast; // Undo the side effect of ReadTag
+            return nextTag;
+        }
+
+        /// <summary>
+        /// Reads a field tag, returning the tag of 0 for "end of stream".
+        /// </summary>
+        /// <remarks>
+        /// If this method returns 0, it doesn't necessarily mean the end of all
+        /// the data in this CodedInputStream; it may be the end of the logical stream
+        /// for an embedded message, for example.
+        /// </remarks>
+        /// <returns>The next field tag, or 0 for end of stream. (0 is never a valid tag.)</returns>
+        public uint ReadTag()
+        {
+            if (hasNextTag)
+            {
+                lastTag = nextTag;
+                hasNextTag = false;
+                return lastTag;
+            }
+
+            // Optimize for the incredibly common case of having at least two bytes left in the buffer,
+            // and those two bytes being enough to get the tag. This will be true for fields up to 4095.
+            if (bufferPos + 2 <= bufferSize)
+            {
+                int tmp = buffer[bufferPos++];
+                if (tmp < 128)
+                {
+                    lastTag = (uint)tmp;
+                }
+                else
+                {
+                    int result = tmp & 0x7f;
+                    if ((tmp = buffer[bufferPos++]) < 128)
+                    {
+                        result |= tmp << 7;
+                        lastTag = (uint) result;
+                    }
+                    else
+                    {
+                        // Nope, rewind and go the potentially slow route.
+                        bufferPos -= 2;
+                        lastTag = ReadRawVarint32();
+                    }
+                }
+            }
+            else
+            {
+                if (IsAtEnd)
+                {
+                    lastTag = 0;
+                    return 0; // This is the only case in which we return 0.
+                }
+
+                lastTag = ReadRawVarint32();
+            }
+            if (lastTag == 0)
+            {
+                // If we actually read zero, that's not a valid tag.
+                throw InvalidProtocolBufferException.InvalidTag();
+            }
+            return lastTag;
+        }
+
+        /// <summary>
+        /// Skips the data for the field with the tag we've just read.
+        /// This should be called directly after <see cref="ReadTag"/>, when
+        /// the caller wishes to skip an unknown field.
+        /// </summary>
+        /// <remarks>
+        /// This method throws <see cref="InvalidProtocolBufferException"/> if the last-read tag was an end-group tag.
+        /// If a caller wishes to skip a group, they should skip the whole group, by calling this method after reading the
+        /// start-group tag. This behavior allows callers to call this method on any field they don't understand, correctly
+        /// resulting in an error if an end-group tag has not been paired with an earlier start-group tag.
+        /// </remarks>
+        /// <exception cref="InvalidProtocolBufferException">The last tag was an end-group tag</exception>
+        /// <exception cref="InvalidOperationException">The last read operation read to the end of the logical stream</exception>
+        public void SkipLastField()
+        {
+            if (lastTag == 0)
+            {
+                throw new InvalidOperationException("SkipLastField cannot be called at the end of a stream");
+            }
+            switch (WireFormat.GetTagWireType(lastTag))
+            {
+                case WireFormat.WireType.StartGroup:
+                    SkipGroup(lastTag);
+                    break;
+                case WireFormat.WireType.EndGroup:
+                    throw new InvalidProtocolBufferException("SkipLastField called on an end-group tag, indicating that the corresponding start-group was missing");
+                case WireFormat.WireType.Fixed32:
+                    ReadFixed32();
+                    break;
+                case WireFormat.WireType.Fixed64:
+                    ReadFixed64();
+                    break;
+                case WireFormat.WireType.LengthDelimited:
+                    var length = ReadLength();
+                    SkipRawBytes(length);
+                    break;
+                case WireFormat.WireType.Varint:
+                    ReadRawVarint32();
+                    break;
+            }
+        }
+
+        private void SkipGroup(uint startGroupTag)
+        {
+            // Note: Currently we expect this to be the way that groups are read. We could put the recursion
+            // depth changes into the ReadTag method instead, potentially...
+            recursionDepth++;
+            if (recursionDepth >= recursionLimit)
+            {
+                throw InvalidProtocolBufferException.RecursionLimitExceeded();
+            }
+            uint tag;
+            while (true)
+            {
+                tag = ReadTag();
+                if (tag == 0)
+                {
+                    throw InvalidProtocolBufferException.TruncatedMessage();
+                }
+                // Can't call SkipLastField for this case- that would throw.
+                if (WireFormat.GetTagWireType(tag) == WireFormat.WireType.EndGroup)
+                {
+                    break;
+                }
+                // This recursion will allow us to handle nested groups.
+                SkipLastField();
+            }
+            int startField = WireFormat.GetTagFieldNumber(startGroupTag);
+            int endField = WireFormat.GetTagFieldNumber(tag);
+            if (startField != endField)
+            {
+                throw new InvalidProtocolBufferException("Mismatched end-group tag. Started with field " + startField + "; ended with field " + endField);
+            }
+            recursionDepth--;
+        }
+
+        /// <summary>
+        /// Reads a double field from the stream.
+        /// </summary>
+        public double ReadDouble()
+        {
+            return BitConverter.Int64BitsToDouble((long) ReadRawLittleEndian64());
+        }
+
+        /// <summary>
+        /// Reads a float field from the stream.
+        /// </summary>
+        public float ReadFloat()
+        {
+            if (BitConverter.IsLittleEndian && 4 <= bufferSize - bufferPos)
+            {
+                float ret = BitConverter.ToSingle(buffer, bufferPos);
+                bufferPos += 4;
+                return ret;
+            }
+            else
+            {
+                byte[] rawBytes = ReadRawBytes(4);
+                if (!BitConverter.IsLittleEndian)
+                {
+                    ByteArray.Reverse(rawBytes);
+                }
+                return BitConverter.ToSingle(rawBytes, 0);
+            }
+        }
+
+        /// <summary>
+        /// Reads a uint64 field from the stream.
+        /// </summary>
+        public ulong ReadUInt64()
+        {
+            return ReadRawVarint64();
+        }
+
+        /// <summary>
+        /// Reads an int64 field from the stream.
+        /// </summary>
+        public long ReadInt64()
+        {
+            return (long) ReadRawVarint64();
+        }
+
+        /// <summary>
+        /// Reads an int32 field from the stream.
+        /// </summary>
+        public int ReadInt32()
+        {
+            return (int) ReadRawVarint32();
+        }
+
+        /// <summary>
+        /// Reads a fixed64 field from the stream.
+        /// </summary>
+        public ulong ReadFixed64()
+        {
+            return ReadRawLittleEndian64();
+        }
+
+        /// <summary>
+        /// Reads a fixed32 field from the stream.
+        /// </summary>
+        public uint ReadFixed32()
+        {
+            return ReadRawLittleEndian32();
+        }
+
+        /// <summary>
+        /// Reads a bool field from the stream.
+        /// </summary>
+        public bool ReadBool()
+        {
+            return ReadRawVarint32() != 0;
+        }
+
+        /// <summary>
+        /// Reads a string field from the stream.
+        /// </summary>
+        public string ReadString()
+        {
+            int length = ReadLength();
+            // No need to read any data for an empty string.
+            if (length == 0)
+            {
+                return "";
+            }
+            if (length <= bufferSize - bufferPos)
+            {
+                // Fast path:  We already have the bytes in a contiguous buffer, so
+                //   just copy directly from it.
+                String result = CodedOutputStream.Utf8Encoding.GetString(buffer, bufferPos, length);
+                bufferPos += length;
+                return result;
+            }
+            // Slow path: Build a byte array first then copy it.
+            return CodedOutputStream.Utf8Encoding.GetString(ReadRawBytes(length), 0, length);
+        }
+
+        /// <summary>
+        /// Reads an embedded message field value from the stream.
+        /// </summary>   
+        public void ReadMessage(IMessage builder)
+        {
+            int length = ReadLength();
+            if (recursionDepth >= recursionLimit)
+            {
+                throw InvalidProtocolBufferException.RecursionLimitExceeded();
+            }
+            int oldLimit = PushLimit(length);
+            ++recursionDepth;
+            builder.MergeFrom(this);
+            CheckReadEndOfStreamTag();
+            // Check that we've read exactly as much data as expected.
+            if (!ReachedLimit)
+            {
+                throw InvalidProtocolBufferException.TruncatedMessage();
+            }
+            --recursionDepth;
+            PopLimit(oldLimit);
+        }
+
+        /// <summary>
+        /// Reads a bytes field value from the stream.
+        /// </summary>   
+        public ByteString ReadBytes()
+        {
+            int length = ReadLength();
+            if (length <= bufferSize - bufferPos && length > 0)
+            {
+                // Fast path:  We already have the bytes in a contiguous buffer, so
+                //   just copy directly from it.
+                ByteString result = ByteString.CopyFrom(buffer, bufferPos, length);
+                bufferPos += length;
+                return result;
+            }
+            else
+            {
+                // Slow path:  Build a byte array and attach it to a new ByteString.
+                return ByteString.AttachBytes(ReadRawBytes(length));
+            }
+        }
+
+        /// <summary>
+        /// Reads a uint32 field value from the stream.
+        /// </summary>   
+        public uint ReadUInt32()
+        {
+            return ReadRawVarint32();
+        }
+
+        /// <summary>
+        /// Reads an enum field value from the stream.
+        /// </summary>   
+        public int ReadEnum()
+        {
+            // Currently just a pass-through, but it's nice to separate it logically from WriteInt32.
+            return (int) ReadRawVarint32();
+        }
+
+        /// <summary>
+        /// Reads an sfixed32 field value from the stream.
+        /// </summary>   
+        public int ReadSFixed32()
+        {
+            return (int) ReadRawLittleEndian32();
+        }
+
+        /// <summary>
+        /// Reads an sfixed64 field value from the stream.
+        /// </summary>   
+        public long ReadSFixed64()
+        {
+            return (long) ReadRawLittleEndian64();
+        }
+
+        /// <summary>
+        /// Reads an sint32 field value from the stream.
+        /// </summary>   
+        public int ReadSInt32()
+        {
+            return DecodeZigZag32(ReadRawVarint32());
+        }
+
+        /// <summary>
+        /// Reads an sint64 field value from the stream.
+        /// </summary>   
+        public long ReadSInt64()
+        {
+            return DecodeZigZag64(ReadRawVarint64());
+        }
+
+        /// <summary>
+        /// Reads a length for length-delimited data.
+        /// </summary>
+        /// <remarks>
+        /// This is internally just reading a varint, but this method exists
+        /// to make the calling code clearer.
+        /// </remarks>
+        public int ReadLength()
+        {
+            return (int) ReadRawVarint32();
+        }
+
+        /// <summary>
+        /// Peeks at the next tag in the stream. If it matches <paramref name="tag"/>,
+        /// the tag is consumed and the method returns <c>true</c>; otherwise, the
+        /// stream is left in the original position and the method returns <c>false</c>.
+        /// </summary>
+        public bool MaybeConsumeTag(uint tag)
+        {
+            if (PeekTag() == tag)
+            {
+                hasNextTag = false;
+                return true;
+            }
+            return false;
+        }
+
+        #endregion
+
+        #region Underlying reading primitives
+
+        /// <summary>
+        /// Same code as ReadRawVarint32, but read each byte individually, checking for
+        /// buffer overflow.
+        /// </summary>
+        private uint SlowReadRawVarint32()
+        {
+            int tmp = ReadRawByte();
+            if (tmp < 128)
+            {
+                return (uint) tmp;
+            }
+            int result = tmp & 0x7f;
+            if ((tmp = ReadRawByte()) < 128)
+            {
+                result |= tmp << 7;
+            }
+            else
+            {
+                result |= (tmp & 0x7f) << 7;
+                if ((tmp = ReadRawByte()) < 128)
+                {
+                    result |= tmp << 14;
+                }
+                else
+                {
+                    result |= (tmp & 0x7f) << 14;
+                    if ((tmp = ReadRawByte()) < 128)
+                    {
+                        result |= tmp << 21;
+                    }
+                    else
+                    {
+                        result |= (tmp & 0x7f) << 21;
+                        result |= (tmp = ReadRawByte()) << 28;
+                        if (tmp >= 128)
+                        {
+                            // Discard upper 32 bits.
+                            for (int i = 0; i < 5; i++)
+                            {
+                                if (ReadRawByte() < 128)
+                                {
+                                    return (uint) result;
+                                }
+                            }
+                            throw InvalidProtocolBufferException.MalformedVarint();
+                        }
+                    }
+                }
+            }
+            return (uint) result;
+        }
+
+        /// <summary>
+        /// Reads a raw Varint from the stream.  If larger than 32 bits, discard the upper bits.
+        /// This method is optimised for the case where we've got lots of data in the buffer.
+        /// That means we can check the size just once, then just read directly from the buffer
+        /// without constant rechecking of the buffer length.
+        /// </summary>
+        internal uint ReadRawVarint32()
+        {
+            if (bufferPos + 5 > bufferSize)
+            {
+                return SlowReadRawVarint32();
+            }
+
+            int tmp = buffer[bufferPos++];
+            if (tmp < 128)
+            {
+                return (uint) tmp;
+            }
+            int result = tmp & 0x7f;
+            if ((tmp = buffer[bufferPos++]) < 128)
+            {
+                result |= tmp << 7;
+            }
+            else
+            {
+                result |= (tmp & 0x7f) << 7;
+                if ((tmp = buffer[bufferPos++]) < 128)
+                {
+                    result |= tmp << 14;
+                }
+                else
+                {
+                    result |= (tmp & 0x7f) << 14;
+                    if ((tmp = buffer[bufferPos++]) < 128)
+                    {
+                        result |= tmp << 21;
+                    }
+                    else
+                    {
+                        result |= (tmp & 0x7f) << 21;
+                        result |= (tmp = buffer[bufferPos++]) << 28;
+                        if (tmp >= 128)
+                        {
+                            // Discard upper 32 bits.
+                            // Note that this has to use ReadRawByte() as we only ensure we've
+                            // got at least 5 bytes at the start of the method. This lets us
+                            // use the fast path in more cases, and we rarely hit this section of code.
+                            for (int i = 0; i < 5; i++)
+                            {
+                                if (ReadRawByte() < 128)
+                                {
+                                    return (uint) result;
+                                }
+                            }
+                            throw InvalidProtocolBufferException.MalformedVarint();
+                        }
+                    }
+                }
+            }
+            return (uint) result;
+        }
+
+        /// <summary>
+        /// Reads a varint from the input one byte at a time, so that it does not
+        /// read any bytes after the end of the varint. If you simply wrapped the
+        /// stream in a CodedInputStream and used ReadRawVarint32(Stream)
+        /// then you would probably end up reading past the end of the varint since
+        /// CodedInputStream buffers its input.
+        /// </summary>
+        /// <param name="input"></param>
+        /// <returns></returns>
+        internal static uint ReadRawVarint32(Stream input)
+        {
+            int result = 0;
+            int offset = 0;
+            for (; offset < 32; offset += 7)
+            {
+                int b = input.ReadByte();
+                if (b == -1)
+                {
+                    throw InvalidProtocolBufferException.TruncatedMessage();
+                }
+                result |= (b & 0x7f) << offset;
+                if ((b & 0x80) == 0)
+                {
+                    return (uint) result;
+                }
+            }
+            // Keep reading up to 64 bits.
+            for (; offset < 64; offset += 7)
+            {
+                int b = input.ReadByte();
+                if (b == -1)
+                {
+                    throw InvalidProtocolBufferException.TruncatedMessage();
+                }
+                if ((b & 0x80) == 0)
+                {
+                    return (uint) result;
+                }
+            }
+            throw InvalidProtocolBufferException.MalformedVarint();
+        }
+
+        /// <summary>
+        /// Reads a raw varint from the stream.
+        /// </summary>
+        internal ulong ReadRawVarint64()
+        {
+            int shift = 0;
+            ulong result = 0;
+            while (shift < 64)
+            {
+                byte b = ReadRawByte();
+                result |= (ulong) (b & 0x7F) << shift;
+                if ((b & 0x80) == 0)
+                {
+                    return result;
+                }
+                shift += 7;
+            }
+            throw InvalidProtocolBufferException.MalformedVarint();
+        }
+
+        /// <summary>
+        /// Reads a 32-bit little-endian integer from the stream.
+        /// </summary>
+        internal uint ReadRawLittleEndian32()
+        {
+            uint b1 = ReadRawByte();
+            uint b2 = ReadRawByte();
+            uint b3 = ReadRawByte();
+            uint b4 = ReadRawByte();
+            return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24);
+        }
+
+        /// <summary>
+        /// Reads a 64-bit little-endian integer from the stream.
+        /// </summary>
+        internal ulong ReadRawLittleEndian64()
+        {
+            ulong b1 = ReadRawByte();
+            ulong b2 = ReadRawByte();
+            ulong b3 = ReadRawByte();
+            ulong b4 = ReadRawByte();
+            ulong b5 = ReadRawByte();
+            ulong b6 = ReadRawByte();
+            ulong b7 = ReadRawByte();
+            ulong b8 = ReadRawByte();
+            return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24)
+                   | (b5 << 32) | (b6 << 40) | (b7 << 48) | (b8 << 56);
+        }
+
+        /// <summary>
+        /// Decode a 32-bit value with ZigZag encoding.
+        /// </summary>
+        /// <remarks>
+        /// ZigZag encodes signed integers into values that can be efficiently
+        /// encoded with varint.  (Otherwise, negative values must be 
+        /// sign-extended to 64 bits to be varint encoded, thus always taking
+        /// 10 bytes on the wire.)
+        /// </remarks>
+        internal static int DecodeZigZag32(uint n)
+        {
+            return (int)(n >> 1) ^ -(int)(n & 1);
+        }
+
+        /// <summary>
+        /// Decode a 32-bit value with ZigZag encoding.
+        /// </summary>
+        /// <remarks>
+        /// ZigZag encodes signed integers into values that can be efficiently
+        /// encoded with varint.  (Otherwise, negative values must be 
+        /// sign-extended to 64 bits to be varint encoded, thus always taking
+        /// 10 bytes on the wire.)
+        /// </remarks>
+        internal static long DecodeZigZag64(ulong n)
+        {
+            return (long)(n >> 1) ^ -(long)(n & 1);
+        }
+        #endregion
+
+        #region Internal reading and buffer management
+
+        /// <summary>
+        /// Sets currentLimit to (current position) + byteLimit. This is called
+        /// when descending into a length-delimited embedded message. The previous
+        /// limit is returned.
+        /// </summary>
+        /// <returns>The old limit.</returns>
+        internal int PushLimit(int byteLimit)
+        {
+            if (byteLimit < 0)
+            {
+                throw InvalidProtocolBufferException.NegativeSize();
+            }
+            byteLimit += totalBytesRetired + bufferPos;
+            int oldLimit = currentLimit;
+            if (byteLimit > oldLimit)
+            {
+                throw InvalidProtocolBufferException.TruncatedMessage();
+            }
+            currentLimit = byteLimit;
+
+            RecomputeBufferSizeAfterLimit();
+
+            return oldLimit;
+        }
+
+        private void RecomputeBufferSizeAfterLimit()
+        {
+            bufferSize += bufferSizeAfterLimit;
+            int bufferEnd = totalBytesRetired + bufferSize;
+            if (bufferEnd > currentLimit)
+            {
+                // Limit is in current buffer.
+                bufferSizeAfterLimit = bufferEnd - currentLimit;
+                bufferSize -= bufferSizeAfterLimit;
+            }
+            else
+            {
+                bufferSizeAfterLimit = 0;
+            }
+        }
+
+        /// <summary>
+        /// Discards the current limit, returning the previous limit.
+        /// </summary>
+        internal void PopLimit(int oldLimit)
+        {
+            currentLimit = oldLimit;
+            RecomputeBufferSizeAfterLimit();
+        }
+
+        /// <summary>
+        /// Returns whether or not all the data before the limit has been read.
+        /// </summary>
+        /// <returns></returns>
+        internal bool ReachedLimit
+        {
+            get
+            {
+                if (currentLimit == int.MaxValue)
+                {
+                    return false;
+                }
+                int currentAbsolutePosition = totalBytesRetired + bufferPos;
+                return currentAbsolutePosition >= currentLimit;
+            }
+        }
+
+        /// <summary>
+        /// Returns true if the stream has reached the end of the input. This is the
+        /// case if either the end of the underlying input source has been reached or
+        /// the stream has reached a limit created using PushLimit.
+        /// </summary>
+        public bool IsAtEnd
+        {
+            get { return bufferPos == bufferSize && !RefillBuffer(false); }
+        }
+
+        /// <summary>
+        /// Called when buffer is empty to read more bytes from the
+        /// input.  If <paramref name="mustSucceed"/> is true, RefillBuffer() gurantees that
+        /// either there will be at least one byte in the buffer when it returns
+        /// or it will throw an exception.  If <paramref name="mustSucceed"/> is false,
+        /// RefillBuffer() returns false if no more bytes were available.
+        /// </summary>
+        /// <param name="mustSucceed"></param>
+        /// <returns></returns>
+        private bool RefillBuffer(bool mustSucceed)
+        {
+            if (bufferPos < bufferSize)
+            {
+                throw new InvalidOperationException("RefillBuffer() called when buffer wasn't empty.");
+            }
+
+            if (totalBytesRetired + bufferSize == currentLimit)
+            {
+                // Oops, we hit a limit.
+                if (mustSucceed)
+                {
+                    throw InvalidProtocolBufferException.TruncatedMessage();
+                }
+                else
+                {
+                    return false;
+                }
+            }
+
+            totalBytesRetired += bufferSize;
+
+            bufferPos = 0;
+            bufferSize = (input == null) ? 0 : input.Read(buffer, 0, buffer.Length);
+            if (bufferSize < 0)
+            {
+                throw new InvalidOperationException("Stream.Read returned a negative count");
+            }
+            if (bufferSize == 0)
+            {
+                if (mustSucceed)
+                {
+                    throw InvalidProtocolBufferException.TruncatedMessage();
+                }
+                else
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                RecomputeBufferSizeAfterLimit();
+                int totalBytesRead =
+                    totalBytesRetired + bufferSize + bufferSizeAfterLimit;
+                if (totalBytesRead > sizeLimit || totalBytesRead < 0)
+                {
+                    throw InvalidProtocolBufferException.SizeLimitExceeded();
+                }
+                return true;
+            }
+        }
+
+        /// <summary>
+        /// Read one byte from the input.
+        /// </summary>
+        /// <exception cref="InvalidProtocolBufferException">
+        /// the end of the stream or the current limit was reached
+        /// </exception>
+        internal byte ReadRawByte()
+        {
+            if (bufferPos == bufferSize)
+            {
+                RefillBuffer(true);
+            }
+            return buffer[bufferPos++];
+        }
+
+        /// <summary>
+        /// Reads a fixed size of bytes from the input.
+        /// </summary>
+        /// <exception cref="InvalidProtocolBufferException">
+        /// the end of the stream or the current limit was reached
+        /// </exception>
+        internal byte[] ReadRawBytes(int size)
+        {
+            if (size < 0)
+            {
+                throw InvalidProtocolBufferException.NegativeSize();
+            }
+
+            if (totalBytesRetired + bufferPos + size > currentLimit)
+            {
+                // Read to the end of the stream (up to the current limit) anyway.
+                SkipRawBytes(currentLimit - totalBytesRetired - bufferPos);
+                // Then fail.
+                throw InvalidProtocolBufferException.TruncatedMessage();
+            }
+
+            if (size <= bufferSize - bufferPos)
+            {
+                // We have all the bytes we need already.
+                byte[] bytes = new byte[size];
+                ByteArray.Copy(buffer, bufferPos, bytes, 0, size);
+                bufferPos += size;
+                return bytes;
+            }
+            else if (size < buffer.Length)
+            {
+                // Reading more bytes than are in the buffer, but not an excessive number
+                // of bytes.  We can safely allocate the resulting array ahead of time.
+
+                // First copy what we have.
+                byte[] bytes = new byte[size];
+                int pos = bufferSize - bufferPos;
+                ByteArray.Copy(buffer, bufferPos, bytes, 0, pos);
+                bufferPos = bufferSize;
+
+                // We want to use RefillBuffer() and then copy from the buffer into our
+                // byte array rather than reading directly into our byte array because
+                // the input may be unbuffered.
+                RefillBuffer(true);
+
+                while (size - pos > bufferSize)
+                {
+                    Buffer.BlockCopy(buffer, 0, bytes, pos, bufferSize);
+                    pos += bufferSize;
+                    bufferPos = bufferSize;
+                    RefillBuffer(true);
+                }
+
+                ByteArray.Copy(buffer, 0, bytes, pos, size - pos);
+                bufferPos = size - pos;
+
+                return bytes;
+            }
+            else
+            {
+                // The size is very large.  For security reasons, we can't allocate the
+                // entire byte array yet.  The size comes directly from the input, so a
+                // maliciously-crafted message could provide a bogus very large size in
+                // order to trick the app into allocating a lot of memory.  We avoid this
+                // by allocating and reading only a small chunk at a time, so that the
+                // malicious message must actually *be* extremely large to cause
+                // problems.  Meanwhile, we limit the allowed size of a message elsewhere.
+
+                // Remember the buffer markers since we'll have to copy the bytes out of
+                // it later.
+                int originalBufferPos = bufferPos;
+                int originalBufferSize = bufferSize;
+
+                // Mark the current buffer consumed.
+                totalBytesRetired += bufferSize;
+                bufferPos = 0;
+                bufferSize = 0;
+
+                // Read all the rest of the bytes we need.
+                int sizeLeft = size - (originalBufferSize - originalBufferPos);
+                List<byte[]> chunks = new List<byte[]>();
+
+                while (sizeLeft > 0)
+                {
+                    byte[] chunk = new byte[Math.Min(sizeLeft, buffer.Length)];
+                    int pos = 0;
+                    while (pos < chunk.Length)
+                    {
+                        int n = (input == null) ? -1 : input.Read(chunk, pos, chunk.Length - pos);
+                        if (n <= 0)
+                        {
+                            throw InvalidProtocolBufferException.TruncatedMessage();
+                        }
+                        totalBytesRetired += n;
+                        pos += n;
+                    }
+                    sizeLeft -= chunk.Length;
+                    chunks.Add(chunk);
+                }
+
+                // OK, got everything.  Now concatenate it all into one buffer.
+                byte[] bytes = new byte[size];
+
+                // Start by copying the leftover bytes from this.buffer.
+                int newPos = originalBufferSize - originalBufferPos;
+                ByteArray.Copy(buffer, originalBufferPos, bytes, 0, newPos);
+
+                // And now all the chunks.
+                foreach (byte[] chunk in chunks)
+                {
+                    Buffer.BlockCopy(chunk, 0, bytes, newPos, chunk.Length);
+                    newPos += chunk.Length;
+                }
+
+                // Done.
+                return bytes;
+            }
+        }
+
+        /// <summary>
+        /// Reads and discards <paramref name="size"/> bytes.
+        /// </summary>
+        /// <exception cref="InvalidProtocolBufferException">the end of the stream
+        /// or the current limit was reached</exception>
+        private void SkipRawBytes(int size)
+        {
+            if (size < 0)
+            {
+                throw InvalidProtocolBufferException.NegativeSize();
+            }
+
+            if (totalBytesRetired + bufferPos + size > currentLimit)
+            {
+                // Read to the end of the stream anyway.
+                SkipRawBytes(currentLimit - totalBytesRetired - bufferPos);
+                // Then fail.
+                throw InvalidProtocolBufferException.TruncatedMessage();
+            }
+
+            if (size <= bufferSize - bufferPos)
+            {
+                // We have all the bytes we need already.
+                bufferPos += size;
+            }
+            else
+            {
+                // Skipping more bytes than are in the buffer.  First skip what we have.
+                int pos = bufferSize - bufferPos;
+
+                // ROK 5/7/2013 Issue #54: should retire all bytes in buffer (bufferSize)
+                // totalBytesRetired += pos;
+                totalBytesRetired += bufferSize;
+                
+                bufferPos = 0;
+                bufferSize = 0;
+
+                // Then skip directly from the InputStream for the rest.
+                if (pos < size)
+                {
+                    if (input == null)
+                    {
+                        throw InvalidProtocolBufferException.TruncatedMessage();
+                    }
+                    SkipImpl(size - pos);
+                    totalBytesRetired += size - pos;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Abstraction of skipping to cope with streams which can't really skip.
+        /// </summary>
+        private void SkipImpl(int amountToSkip)
+        {
+            if (input.CanSeek)
+            {
+                long previousPosition = input.Position;
+                input.Position += amountToSkip;
+                if (input.Position != previousPosition + amountToSkip)
+                {
+                    throw InvalidProtocolBufferException.TruncatedMessage();
+                }
+            }
+            else
+            {
+                byte[] skipBuffer = new byte[Math.Min(1024, amountToSkip)];
+                while (amountToSkip > 0)
+                {
+                    int bytesRead = input.Read(skipBuffer, 0, Math.Min(skipBuffer.Length, amountToSkip));
+                    if (bytesRead <= 0)
+                    {
+                        throw InvalidProtocolBufferException.TruncatedMessage();
+                    }
+                    amountToSkip -= bytesRead;
+                }
+            }
+        }
+
+        #endregion
+    }
+}

+ 304 - 0
Server/ThirdParty/Google.Protobuf/CodedOutputStream.ComputeSize.cs

@@ -0,0 +1,304 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+
+namespace Google.Protobuf
+{
+    // This part of CodedOutputStream provides all the static entry points that are used
+    // by generated code and internally to compute the size of messages prior to being
+    // written to an instance of CodedOutputStream.
+    public sealed partial class CodedOutputStream
+    {
+        private const int LittleEndian64Size = 8;
+        private const int LittleEndian32Size = 4;        
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode a
+        /// double field, including the tag.
+        /// </summary>
+        public static int ComputeDoubleSize(double value)
+        {
+            return LittleEndian64Size;
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode a
+        /// float field, including the tag.
+        /// </summary>
+        public static int ComputeFloatSize(float value)
+        {
+            return LittleEndian32Size;
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode a
+        /// uint64 field, including the tag.
+        /// </summary>
+        public static int ComputeUInt64Size(ulong value)
+        {
+            return ComputeRawVarint64Size(value);
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode an
+        /// int64 field, including the tag.
+        /// </summary>
+        public static int ComputeInt64Size(long value)
+        {
+            return ComputeRawVarint64Size((ulong) value);
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode an
+        /// int32 field, including the tag.
+        /// </summary>
+        public static int ComputeInt32Size(int value)
+        {
+            if (value >= 0)
+            {
+                return ComputeRawVarint32Size((uint) value);
+            }
+            else
+            {
+                // Must sign-extend.
+                return 10;
+            }
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode a
+        /// fixed64 field, including the tag.
+        /// </summary>
+        public static int ComputeFixed64Size(ulong value)
+        {
+            return LittleEndian64Size;
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode a
+        /// fixed32 field, including the tag.
+        /// </summary>
+        public static int ComputeFixed32Size(uint value)
+        {
+            return LittleEndian32Size;
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode a
+        /// bool field, including the tag.
+        /// </summary>
+        public static int ComputeBoolSize(bool value)
+        {
+            return 1;
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode a
+        /// string field, including the tag.
+        /// </summary>
+        public static int ComputeStringSize(String value)
+        {
+            int byteArraySize = Utf8Encoding.GetByteCount(value);
+            return ComputeLengthSize(byteArraySize) + byteArraySize;
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode a
+        /// group field, including the tag.
+        /// </summary>
+        public static int ComputeGroupSize(IMessage value)
+        {
+            return value.CalculateSize();
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode an
+        /// embedded message field, including the tag.
+        /// </summary>
+        public static int ComputeMessageSize(IMessage value)
+        {
+            int size = value.CalculateSize();
+            return ComputeLengthSize(size) + size;
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode a
+        /// bytes field, including the tag.
+        /// </summary>
+        public static int ComputeBytesSize(ByteString value)
+        {
+            return ComputeLengthSize(value.Length) + value.Length;
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode a
+        /// uint32 field, including the tag.
+        /// </summary>
+        public static int ComputeUInt32Size(uint value)
+        {
+            return ComputeRawVarint32Size(value);
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode a
+        /// enum field, including the tag. The caller is responsible for
+        /// converting the enum value to its numeric value.
+        /// </summary>
+        public static int ComputeEnumSize(int value)
+        {
+            // Currently just a pass-through, but it's nice to separate it logically.
+            return ComputeInt32Size(value);
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode an
+        /// sfixed32 field, including the tag.
+        /// </summary>
+        public static int ComputeSFixed32Size(int value)
+        {
+            return LittleEndian32Size;
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode an
+        /// sfixed64 field, including the tag.
+        /// </summary>
+        public static int ComputeSFixed64Size(long value)
+        {
+            return LittleEndian64Size;
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode an
+        /// sint32 field, including the tag.
+        /// </summary>
+        public static int ComputeSInt32Size(int value)
+        {
+            return ComputeRawVarint32Size(EncodeZigZag32(value));
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode an
+        /// sint64 field, including the tag.
+        /// </summary>
+        public static int ComputeSInt64Size(long value)
+        {
+            return ComputeRawVarint64Size(EncodeZigZag64(value));
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode a length,
+        /// as written by <see cref="WriteLength"/>.
+        /// </summary>
+        public static int ComputeLengthSize(int length)
+        {
+            return ComputeRawVarint32Size((uint) length);
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode a varint.
+        /// </summary>
+        public static int ComputeRawVarint32Size(uint value)
+        {
+            if ((value & (0xffffffff << 7)) == 0)
+            {
+                return 1;
+            }
+            if ((value & (0xffffffff << 14)) == 0)
+            {
+                return 2;
+            }
+            if ((value & (0xffffffff << 21)) == 0)
+            {
+                return 3;
+            }
+            if ((value & (0xffffffff << 28)) == 0)
+            {
+                return 4;
+            }
+            return 5;
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode a varint.
+        /// </summary>
+        public static int ComputeRawVarint64Size(ulong value)
+        {
+            if ((value & (0xffffffffffffffffL << 7)) == 0)
+            {
+                return 1;
+            }
+            if ((value & (0xffffffffffffffffL << 14)) == 0)
+            {
+                return 2;
+            }
+            if ((value & (0xffffffffffffffffL << 21)) == 0)
+            {
+                return 3;
+            }
+            if ((value & (0xffffffffffffffffL << 28)) == 0)
+            {
+                return 4;
+            }
+            if ((value & (0xffffffffffffffffL << 35)) == 0)
+            {
+                return 5;
+            }
+            if ((value & (0xffffffffffffffffL << 42)) == 0)
+            {
+                return 6;
+            }
+            if ((value & (0xffffffffffffffffL << 49)) == 0)
+            {
+                return 7;
+            }
+            if ((value & (0xffffffffffffffffL << 56)) == 0)
+            {
+                return 8;
+            }
+            if ((value & (0xffffffffffffffffL << 63)) == 0)
+            {
+                return 9;
+            }
+            return 10;
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode a tag.
+        /// </summary>
+        public static int ComputeTagSize(int fieldNumber)
+        {
+            return ComputeRawVarint32Size(WireFormat.MakeTag(fieldNumber, 0));
+        }
+    }
+}

+ 761 - 0
Server/ThirdParty/Google.Protobuf/CodedOutputStream.cs

@@ -0,0 +1,761 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using Google.Protobuf.Collections;
+using System;
+using System.IO;
+using System.Text;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Encodes and writes protocol message fields.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// This class is generally used by generated code to write appropriate
+    /// primitives to the stream. It effectively encapsulates the lowest
+    /// levels of protocol buffer format. Unlike some other implementations,
+    /// this does not include combined "write tag and value" methods. Generated
+    /// code knows the exact byte representations of the tags they're going to write,
+    /// so there's no need to re-encode them each time. Manually-written code calling
+    /// this class should just call one of the <c>WriteTag</c> overloads before each value.
+    /// </para>
+    /// <para>
+    /// Repeated fields and map fields are not handled by this class; use <c>RepeatedField&lt;T&gt;</c>
+    /// and <c>MapField&lt;TKey, TValue&gt;</c> to serialize such fields.
+    /// </para>
+    /// </remarks>
+    public sealed partial class CodedOutputStream : IDisposable
+    {
+        // "Local" copy of Encoding.UTF8, for efficiency. (Yes, it makes a difference.)
+        internal static readonly Encoding Utf8Encoding = Encoding.UTF8;
+
+        /// <summary>
+        /// The buffer size used by CreateInstance(Stream).
+        /// </summary>
+        public static readonly int DefaultBufferSize = 4096;
+
+        private readonly bool leaveOpen;
+        private readonly byte[] buffer;
+        private readonly int limit;
+        private int position;
+        private readonly Stream output;
+
+        #region Construction
+        /// <summary>
+        /// Creates a new CodedOutputStream that writes directly to the given
+        /// byte array. If more bytes are written than fit in the array,
+        /// OutOfSpaceException will be thrown.
+        /// </summary>
+        public CodedOutputStream(byte[] flatArray) : this(flatArray, 0, flatArray.Length)
+        {
+        }
+
+        /// <summary>
+        /// Creates a new CodedOutputStream that writes directly to the given
+        /// byte array slice. If more bytes are written than fit in the array,
+        /// OutOfSpaceException will be thrown.
+        /// </summary>
+        private CodedOutputStream(byte[] buffer, int offset, int length)
+        {
+            this.output = null;
+            this.buffer = buffer;
+            this.position = offset;
+            this.limit = offset + length;
+            leaveOpen = true; // Simple way of avoiding trying to dispose of a null reference
+        }
+
+        private CodedOutputStream(Stream output, byte[] buffer, bool leaveOpen)
+        {
+            this.output = ProtoPreconditions.CheckNotNull(output, "output");
+            this.buffer = buffer;
+            this.position = 0;
+            this.limit = buffer.Length;
+            this.leaveOpen = leaveOpen;
+        }
+
+        /// <summary>
+        /// Creates a new <see cref="CodedOutputStream" /> which write to the given stream, and disposes of that
+        /// stream when the returned <c>CodedOutputStream</c> is disposed.
+        /// </summary>
+        /// <param name="output">The stream to write to. It will be disposed when the returned <c>CodedOutputStream is disposed.</c></param>
+        public CodedOutputStream(Stream output) : this(output, DefaultBufferSize, false)
+        {
+        }
+
+        /// <summary>
+        /// Creates a new CodedOutputStream which write to the given stream and uses
+        /// the specified buffer size.
+        /// </summary>
+        /// <param name="output">The stream to write to. It will be disposed when the returned <c>CodedOutputStream is disposed.</c></param>
+        /// <param name="bufferSize">The size of buffer to use internally.</param>
+        public CodedOutputStream(Stream output, int bufferSize) : this(output, new byte[bufferSize], false)
+        {
+        }
+
+        /// <summary>
+        /// Creates a new CodedOutputStream which write to the given stream.
+        /// </summary>
+        /// <param name="output">The stream to write to.</param>
+        /// <param name="leaveOpen">If <c>true</c>, <paramref name="output"/> is left open when the returned <c>CodedOutputStream</c> is disposed;
+        /// if <c>false</c>, the provided stream is disposed as well.</param>
+        public CodedOutputStream(Stream output, bool leaveOpen) : this(output, DefaultBufferSize, leaveOpen)
+        {
+        }
+
+        /// <summary>
+        /// Creates a new CodedOutputStream which write to the given stream and uses
+        /// the specified buffer size.
+        /// </summary>
+        /// <param name="output">The stream to write to.</param>
+        /// <param name="bufferSize">The size of buffer to use internally.</param>
+        /// <param name="leaveOpen">If <c>true</c>, <paramref name="output"/> is left open when the returned <c>CodedOutputStream</c> is disposed;
+        /// if <c>false</c>, the provided stream is disposed as well.</param>
+        public CodedOutputStream(Stream output, int bufferSize, bool leaveOpen) : this(output, new byte[bufferSize], leaveOpen)
+        {
+        }
+        #endregion
+
+        /// <summary>
+        /// Returns the current position in the stream, or the position in the output buffer
+        /// </summary>
+        public long Position
+        {
+            get
+            {
+                if (output != null)
+                {
+                    return output.Position + position;
+                }
+                return position;
+            }
+        }
+
+        #region Writing of values (not including tags)
+
+        /// <summary>
+        /// Writes a double field value, without a tag, to the stream.
+        /// </summary>
+        /// <param name="value">The value to write</param>
+        public void WriteDouble(double value)
+        {
+            WriteRawLittleEndian64((ulong)BitConverter.DoubleToInt64Bits(value));
+        }
+
+        /// <summary>
+        /// Writes a float field value, without a tag, to the stream.
+        /// </summary>
+        /// <param name="value">The value to write</param>
+        public void WriteFloat(float value)
+        {
+            byte[] rawBytes = BitConverter.GetBytes(value);
+            if (!BitConverter.IsLittleEndian)
+            {
+                ByteArray.Reverse(rawBytes);
+            }
+
+            if (limit - position >= 4)
+            {
+                buffer[position++] = rawBytes[0];
+                buffer[position++] = rawBytes[1];
+                buffer[position++] = rawBytes[2];
+                buffer[position++] = rawBytes[3];
+            }
+            else
+            {
+                WriteRawBytes(rawBytes, 0, 4);
+            }
+        }
+
+        /// <summary>
+        /// Writes a uint64 field value, without a tag, to the stream.
+        /// </summary>
+        /// <param name="value">The value to write</param>
+        public void WriteUInt64(ulong value)
+        {
+            WriteRawVarint64(value);
+        }
+
+        /// <summary>
+        /// Writes an int64 field value, without a tag, to the stream.
+        /// </summary>
+        /// <param name="value">The value to write</param>
+        public void WriteInt64(long value)
+        {
+            WriteRawVarint64((ulong) value);
+        }
+
+        /// <summary>
+        /// Writes an int32 field value, without a tag, to the stream.
+        /// </summary>
+        /// <param name="value">The value to write</param>
+        public void WriteInt32(int value)
+        {
+            if (value >= 0)
+            {
+                WriteRawVarint32((uint) value);
+            }
+            else
+            {
+                // Must sign-extend.
+                WriteRawVarint64((ulong) value);
+            }
+        }
+
+        /// <summary>
+        /// Writes a fixed64 field value, without a tag, to the stream.
+        /// </summary>
+        /// <param name="value">The value to write</param>
+        public void WriteFixed64(ulong value)
+        {
+            WriteRawLittleEndian64(value);
+        }
+
+        /// <summary>
+        /// Writes a fixed32 field value, without a tag, to the stream.
+        /// </summary>
+        /// <param name="value">The value to write</param>
+        public void WriteFixed32(uint value)
+        {
+            WriteRawLittleEndian32(value);
+        }
+
+        /// <summary>
+        /// Writes a bool field value, without a tag, to the stream.
+        /// </summary>
+        /// <param name="value">The value to write</param>
+        public void WriteBool(bool value)
+        {
+            WriteRawByte(value ? (byte) 1 : (byte) 0);
+        }
+
+        /// <summary>
+        /// Writes a string field value, without a tag, to the stream.
+        /// The data is length-prefixed.
+        /// </summary>
+        /// <param name="value">The value to write</param>
+        public void WriteString(string value)
+        {
+            // Optimise the case where we have enough space to write
+            // the string directly to the buffer, which should be common.
+            int length = Utf8Encoding.GetByteCount(value);
+            WriteLength(length);
+            if (limit - position >= length)
+            {
+                if (length == value.Length) // Must be all ASCII...
+                {
+                    for (int i = 0; i < length; i++)
+                    {
+                        buffer[position + i] = (byte)value[i];
+                    }
+                }
+                else
+                {
+                    Utf8Encoding.GetBytes(value, 0, value.Length, buffer, position);
+                }
+                position += length;
+            }
+            else
+            {
+                byte[] bytes = Utf8Encoding.GetBytes(value);
+                WriteRawBytes(bytes);
+            }
+        }
+
+        /// <summary>
+        /// Writes a message, without a tag, to the stream.
+        /// The data is length-prefixed.
+        /// </summary>
+        /// <param name="value">The value to write</param>
+        public void WriteMessage(IMessage value)
+        {
+            WriteLength(value.CalculateSize());
+            value.WriteTo(this);
+        }
+
+        /// <summary>
+        /// Write a byte string, without a tag, to the stream.
+        /// The data is length-prefixed.
+        /// </summary>
+        /// <param name="value">The value to write</param>
+        public void WriteBytes(ByteString value)
+        {
+            WriteLength(value.Length);
+            value.WriteRawBytesTo(this);
+        }
+
+        /// <summary>
+        /// Writes a uint32 value, without a tag, to the stream.
+        /// </summary>
+        /// <param name="value">The value to write</param>
+        public void WriteUInt32(uint value)
+        {
+            WriteRawVarint32(value);
+        }
+
+        /// <summary>
+        /// Writes an enum value, without a tag, to the stream.
+        /// </summary>
+        /// <param name="value">The value to write</param>
+        public void WriteEnum(int value)
+        {
+            WriteInt32(value);
+        }
+
+        /// <summary>
+        /// Writes an sfixed32 value, without a tag, to the stream.
+        /// </summary>
+        /// <param name="value">The value to write.</param>
+        public void WriteSFixed32(int value)
+        {
+            WriteRawLittleEndian32((uint) value);
+        }
+
+        /// <summary>
+        /// Writes an sfixed64 value, without a tag, to the stream.
+        /// </summary>
+        /// <param name="value">The value to write</param>
+        public void WriteSFixed64(long value)
+        {
+            WriteRawLittleEndian64((ulong) value);
+        }
+
+        /// <summary>
+        /// Writes an sint32 value, without a tag, to the stream.
+        /// </summary>
+        /// <param name="value">The value to write</param>
+        public void WriteSInt32(int value)
+        {
+            WriteRawVarint32(EncodeZigZag32(value));
+        }
+
+        /// <summary>
+        /// Writes an sint64 value, without a tag, to the stream.
+        /// </summary>
+        /// <param name="value">The value to write</param>
+        public void WriteSInt64(long value)
+        {
+            WriteRawVarint64(EncodeZigZag64(value));
+        }
+
+        /// <summary>
+        /// Writes a length (in bytes) for length-delimited data.
+        /// </summary>
+        /// <remarks>
+        /// This method simply writes a rawint, but exists for clarity in calling code.
+        /// </remarks>
+        /// <param name="length">Length value, in bytes.</param>
+        public void WriteLength(int length)
+        {
+            WriteRawVarint32((uint) length);
+        }
+
+        #endregion
+
+        #region Raw tag writing
+        /// <summary>
+        /// Encodes and writes a tag.
+        /// </summary>
+        /// <param name="fieldNumber">The number of the field to write the tag for</param>
+        /// <param name="type">The wire format type of the tag to write</param>
+        public void WriteTag(int fieldNumber, WireFormat.WireType type)
+        {
+            WriteRawVarint32(WireFormat.MakeTag(fieldNumber, type));
+        }
+
+        /// <summary>
+        /// Writes an already-encoded tag.
+        /// </summary>
+        /// <param name="tag">The encoded tag</param>
+        public void WriteTag(uint tag)
+        {
+            WriteRawVarint32(tag);
+        }
+
+        /// <summary>
+        /// Writes the given single-byte tag directly to the stream.
+        /// </summary>
+        /// <param name="b1">The encoded tag</param>
+        public void WriteRawTag(byte b1)
+        {
+            WriteRawByte(b1);
+        }
+
+        /// <summary>
+        /// Writes the given two-byte tag directly to the stream.
+        /// </summary>
+        /// <param name="b1">The first byte of the encoded tag</param>
+        /// <param name="b2">The second byte of the encoded tag</param>
+        public void WriteRawTag(byte b1, byte b2)
+        {
+            WriteRawByte(b1);
+            WriteRawByte(b2);
+        }
+
+        /// <summary>
+        /// Writes the given three-byte tag directly to the stream.
+        /// </summary>
+        /// <param name="b1">The first byte of the encoded tag</param>
+        /// <param name="b2">The second byte of the encoded tag</param>
+        /// <param name="b3">The third byte of the encoded tag</param>
+        public void WriteRawTag(byte b1, byte b2, byte b3)
+        {
+            WriteRawByte(b1);
+            WriteRawByte(b2);
+            WriteRawByte(b3);
+        }
+
+        /// <summary>
+        /// Writes the given four-byte tag directly to the stream.
+        /// </summary>
+        /// <param name="b1">The first byte of the encoded tag</param>
+        /// <param name="b2">The second byte of the encoded tag</param>
+        /// <param name="b3">The third byte of the encoded tag</param>
+        /// <param name="b4">The fourth byte of the encoded tag</param>
+        public void WriteRawTag(byte b1, byte b2, byte b3, byte b4)
+        {
+            WriteRawByte(b1);
+            WriteRawByte(b2);
+            WriteRawByte(b3);
+            WriteRawByte(b4);
+        }
+
+        /// <summary>
+        /// Writes the given five-byte tag directly to the stream.
+        /// </summary>
+        /// <param name="b1">The first byte of the encoded tag</param>
+        /// <param name="b2">The second byte of the encoded tag</param>
+        /// <param name="b3">The third byte of the encoded tag</param>
+        /// <param name="b4">The fourth byte of the encoded tag</param>
+        /// <param name="b5">The fifth byte of the encoded tag</param>
+        public void WriteRawTag(byte b1, byte b2, byte b3, byte b4, byte b5)
+        {
+            WriteRawByte(b1);
+            WriteRawByte(b2);
+            WriteRawByte(b3);
+            WriteRawByte(b4);
+            WriteRawByte(b5);
+        }
+        #endregion
+
+        #region Underlying writing primitives
+        /// <summary>
+        /// Writes a 32 bit value as a varint. The fast route is taken when
+        /// there's enough buffer space left to whizz through without checking
+        /// for each byte; otherwise, we resort to calling WriteRawByte each time.
+        /// </summary>
+        internal void WriteRawVarint32(uint value)
+        {
+            // Optimize for the common case of a single byte value
+            if (value < 128 && position < limit)
+            {
+                buffer[position++] = (byte)value;
+                return;
+            }
+
+            while (value > 127 && position < limit)
+            {
+                buffer[position++] = (byte) ((value & 0x7F) | 0x80);
+                value >>= 7;
+            }
+            while (value > 127)
+            {
+                WriteRawByte((byte) ((value & 0x7F) | 0x80));
+                value >>= 7;
+            }
+            if (position < limit)
+            {
+                buffer[position++] = (byte) value;
+            }
+            else
+            {
+                WriteRawByte((byte) value);
+            }
+        }
+
+        internal void WriteRawVarint64(ulong value)
+        {
+            while (value > 127 && position < limit)
+            {
+                buffer[position++] = (byte) ((value & 0x7F) | 0x80);
+                value >>= 7;
+            }
+            while (value > 127)
+            {
+                WriteRawByte((byte) ((value & 0x7F) | 0x80));
+                value >>= 7;
+            }
+            if (position < limit)
+            {
+                buffer[position++] = (byte) value;
+            }
+            else
+            {
+                WriteRawByte((byte) value);
+            }
+        }
+
+        internal void WriteRawLittleEndian32(uint value)
+        {
+            if (position + 4 > limit)
+            {
+                WriteRawByte((byte) value);
+                WriteRawByte((byte) (value >> 8));
+                WriteRawByte((byte) (value >> 16));
+                WriteRawByte((byte) (value >> 24));
+            }
+            else
+            {
+                buffer[position++] = ((byte) value);
+                buffer[position++] = ((byte) (value >> 8));
+                buffer[position++] = ((byte) (value >> 16));
+                buffer[position++] = ((byte) (value >> 24));
+            }
+        }
+
+        internal void WriteRawLittleEndian64(ulong value)
+        {
+            if (position + 8 > limit)
+            {
+                WriteRawByte((byte) value);
+                WriteRawByte((byte) (value >> 8));
+                WriteRawByte((byte) (value >> 16));
+                WriteRawByte((byte) (value >> 24));
+                WriteRawByte((byte) (value >> 32));
+                WriteRawByte((byte) (value >> 40));
+                WriteRawByte((byte) (value >> 48));
+                WriteRawByte((byte) (value >> 56));
+            }
+            else
+            {
+                buffer[position++] = ((byte) value);
+                buffer[position++] = ((byte) (value >> 8));
+                buffer[position++] = ((byte) (value >> 16));
+                buffer[position++] = ((byte) (value >> 24));
+                buffer[position++] = ((byte) (value >> 32));
+                buffer[position++] = ((byte) (value >> 40));
+                buffer[position++] = ((byte) (value >> 48));
+                buffer[position++] = ((byte) (value >> 56));
+            }
+        }
+
+        internal void WriteRawByte(byte value)
+        {
+            if (position == limit)
+            {
+                RefreshBuffer();
+            }
+
+            buffer[position++] = value;
+        }
+
+        internal void WriteRawByte(uint value)
+        {
+            WriteRawByte((byte) value);
+        }
+
+        /// <summary>
+        /// Writes out an array of bytes.
+        /// </summary>
+        internal void WriteRawBytes(byte[] value)
+        {
+            WriteRawBytes(value, 0, value.Length);
+        }
+
+        /// <summary>
+        /// Writes out part of an array of bytes.
+        /// </summary>
+        internal void WriteRawBytes(byte[] value, int offset, int length)
+        {
+            if (limit - position >= length)
+            {
+                ByteArray.Copy(value, offset, buffer, position, length);
+                // We have room in the current buffer.
+                position += length;
+            }
+            else
+            {
+                // Write extends past current buffer.  Fill the rest of this buffer and
+                // flush.
+                int bytesWritten = limit - position;
+                ByteArray.Copy(value, offset, buffer, position, bytesWritten);
+                offset += bytesWritten;
+                length -= bytesWritten;
+                position = limit;
+                RefreshBuffer();
+
+                // Now deal with the rest.
+                // Since we have an output stream, this is our buffer
+                // and buffer offset == 0
+                if (length <= limit)
+                {
+                    // Fits in new buffer.
+                    ByteArray.Copy(value, offset, buffer, 0, length);
+                    position = length;
+                }
+                else
+                {
+                    // Write is very big.  Let's do it all at once.
+                    output.Write(value, offset, length);
+                }
+            }
+        }
+
+        #endregion
+
+        /// <summary>
+        /// Encode a 32-bit value with ZigZag encoding.
+        /// </summary>
+        /// <remarks>
+        /// ZigZag encodes signed integers into values that can be efficiently
+        /// encoded with varint.  (Otherwise, negative values must be 
+        /// sign-extended to 64 bits to be varint encoded, thus always taking
+        /// 10 bytes on the wire.)
+        /// </remarks>
+        internal static uint EncodeZigZag32(int n)
+        {
+            // Note:  the right-shift must be arithmetic
+            return (uint) ((n << 1) ^ (n >> 31));
+        }
+
+        /// <summary>
+        /// Encode a 64-bit value with ZigZag encoding.
+        /// </summary>
+        /// <remarks>
+        /// ZigZag encodes signed integers into values that can be efficiently
+        /// encoded with varint.  (Otherwise, negative values must be 
+        /// sign-extended to 64 bits to be varint encoded, thus always taking
+        /// 10 bytes on the wire.)
+        /// </remarks>
+        internal static ulong EncodeZigZag64(long n)
+        {
+            return (ulong) ((n << 1) ^ (n >> 63));
+        }
+
+        private void RefreshBuffer()
+        {
+            if (output == null)
+            {
+                // We're writing to a single buffer.
+                throw new OutOfSpaceException();
+            }
+
+            // Since we have an output stream, this is our buffer
+            // and buffer offset == 0
+            output.Write(buffer, 0, position);
+            position = 0;
+        }
+
+        /// <summary>
+        /// Indicates that a CodedOutputStream wrapping a flat byte array
+        /// ran out of space.
+        /// </summary>
+        public sealed class OutOfSpaceException : IOException
+        {
+            internal OutOfSpaceException()
+                : base("CodedOutputStream was writing to a flat byte array and ran out of space.")
+            {
+            }
+        }
+
+        /// <summary>
+        /// Flushes any buffered data and optionally closes the underlying stream, if any.
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// By default, any underlying stream is closed by this method. To configure this behaviour,
+        /// use a constructor overload with a <c>leaveOpen</c> parameter. If this instance does not
+        /// have an underlying stream, this method does nothing.
+        /// </para>
+        /// <para>
+        /// For the sake of efficiency, calling this method does not prevent future write calls - but
+        /// if a later write ends up writing to a stream which has been disposed, that is likely to
+        /// fail. It is recommend that you not call any other methods after this.
+        /// </para>
+        /// </remarks>
+        public void Dispose()
+        {
+            Flush();
+            if (!leaveOpen)
+            {
+                output.Dispose();
+            }
+        }
+
+        /// <summary>
+        /// Flushes any buffered data to the underlying stream (if there is one).
+        /// </summary>
+        public void Flush()
+        {
+            if (output != null)
+            {
+                RefreshBuffer();
+            }
+        }
+
+        /// <summary>
+        /// Verifies that SpaceLeft returns zero. It's common to create a byte array
+        /// that is exactly big enough to hold a message, then write to it with
+        /// a CodedOutputStream. Calling CheckNoSpaceLeft after writing verifies that
+        /// the message was actually as big as expected, which can help bugs.
+        /// </summary>
+        public void CheckNoSpaceLeft()
+        {
+            if (SpaceLeft != 0)
+            {
+                throw new InvalidOperationException("Did not write as much data as expected.");
+            }
+        }
+
+        /// <summary>
+        /// If writing to a flat array, returns the space left in the array. Otherwise,
+        /// throws an InvalidOperationException.
+        /// </summary>
+        public int SpaceLeft
+        {
+            get
+            {
+                if (output == null)
+                {
+                    return limit - position;
+                }
+                else
+                {
+                    throw new InvalidOperationException(
+                        "SpaceLeft can only be called on CodedOutputStreams that are " +
+                        "writing to a flat array.");
+                }
+            }
+        }
+    }
+}

+ 580 - 0
Server/ThirdParty/Google.Protobuf/Collections/RepeatedField.cs

@@ -0,0 +1,580 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+
+namespace Google.Protobuf.Collections
+{
+    /// <summary>
+    /// The contents of a repeated field: essentially, a collection with some extra
+    /// restrictions (no null values) and capabilities (deep cloning).
+    /// </summary>
+    /// <remarks>
+    /// This implementation does not generally prohibit the use of types which are not
+    /// supported by Protocol Buffers but nor does it guarantee that all operations will work in such cases.
+    /// </remarks>
+    /// <typeparam name="T">The element type of the repeated field.</typeparam>
+    public sealed class RepeatedField<T> : IList<T>, IList 
+    {
+        private static readonly T[] EmptyArray = new T[0];
+        private const int MinArraySize = 8;
+
+        public T[] array = EmptyArray;
+        public int count = 0;
+
+        /// <summary>
+        /// Adds the entries from the given input stream, decoding them with the specified codec.
+        /// </summary>
+        /// <param name="input">The input stream to read from.</param>
+        /// <param name="codec">The codec to use in order to read each entry.</param>
+        public void AddEntriesFrom(CodedInputStream input, FieldCodec<T> codec)
+        {
+            // TODO: Inline some of the Add code, so we can avoid checking the size on every
+            // iteration.
+            uint tag = input.LastTag;
+            var reader = codec.ValueReader;
+            // Non-nullable value types can be packed or not.
+            if (FieldCodec<T>.IsPackedRepeatedField(tag))
+            {
+                int length = input.ReadLength();
+                if (length > 0)
+                {
+                    int oldLimit = input.PushLimit(length);
+                    while (!input.ReachedLimit)
+                    {
+                        Add(reader(input));
+                    }
+                    input.PopLimit(oldLimit);
+                }
+                // Empty packed field. Odd, but valid - just ignore.
+            }
+            else
+            {
+                // Not packed... (possibly not packable)
+                do
+                {
+                    Add(reader(input));
+                } while (input.MaybeConsumeTag(tag));
+            }
+        }
+
+        /// <summary>
+        /// Calculates the size of this collection based on the given codec.
+        /// </summary>
+        /// <param name="codec">The codec to use when encoding each field.</param>
+        /// <returns>The number of bytes that would be written to a <see cref="CodedOutputStream"/> by <see cref="WriteTo"/>,
+        /// using the same codec.</returns>
+        public int CalculateSize(FieldCodec<T> codec)
+        {
+            if (count == 0)
+            {
+                return 0;
+            }
+            uint tag = codec.Tag;
+            if (codec.PackedRepeatedField)
+            {
+                int dataSize = CalculatePackedDataSize(codec);
+                return CodedOutputStream.ComputeRawVarint32Size(tag) +
+                    CodedOutputStream.ComputeLengthSize(dataSize) +
+                    dataSize;
+            }
+            else
+            {
+                var sizeCalculator = codec.ValueSizeCalculator;
+                int size = count * CodedOutputStream.ComputeRawVarint32Size(tag);
+                for (int i = 0; i < count; i++)
+                {
+                    size += sizeCalculator(array[i]);
+                }
+                return size;
+            }
+        }
+
+        private int CalculatePackedDataSize(FieldCodec<T> codec)
+        {
+            int fixedSize = codec.FixedSize;
+            if (fixedSize == 0)
+            {
+                var calculator = codec.ValueSizeCalculator;
+                int tmp = 0;
+                for (int i = 0; i < count; i++)
+                {
+                    tmp += calculator(array[i]);
+                }
+                return tmp;
+            }
+            else
+            {
+                return fixedSize * Count;
+            }
+        }
+
+        /// <summary>
+        /// Writes the contents of this collection to the given <see cref="CodedOutputStream"/>,
+        /// encoding each value using the specified codec.
+        /// </summary>
+        /// <param name="output">The output stream to write to.</param>
+        /// <param name="codec">The codec to use when encoding each value.</param>
+        public void WriteTo(CodedOutputStream output, FieldCodec<T> codec)
+        {
+            if (count == 0)
+            {
+                return;
+            }
+            var writer = codec.ValueWriter;
+            var tag = codec.Tag;
+            if (codec.PackedRepeatedField)
+            {
+                // Packed primitive type
+                uint size = (uint)CalculatePackedDataSize(codec);
+                output.WriteTag(tag);
+                output.WriteRawVarint32(size);
+                for (int i = 0; i < count; i++)
+                {
+                    writer(output, array[i]);
+                }
+            }
+            else
+            {
+                // Not packed: a simple tag/value pair for each value.
+                // Can't use codec.WriteTagAndValue, as that omits default values.
+                for (int i = 0; i < count; i++)
+                {
+                    output.WriteTag(tag);
+                    writer(output, array[i]);
+                }
+            }
+        }
+
+        private void EnsureSize(int size)
+        {
+            if (array.Length < size)
+            {
+                size = Math.Max(size, MinArraySize);
+                int newSize = Math.Max(array.Length * 2, size);
+                var tmp = new T[newSize];
+                Array.Copy(array, 0, tmp, 0, array.Length);
+                array = tmp;
+            }
+        }
+
+        /// <summary>
+        /// Adds the specified item to the collection.
+        /// </summary>
+        /// <param name="item">The item to add.</param>
+        public void Add(T item)
+        {
+            ProtoPreconditions.CheckNotNullUnconstrained(item, "item");
+            EnsureSize(count + 1);
+            array[count++] = item;
+        }
+
+        /// <summary>
+        /// Removes all items from the collection.
+        /// </summary>
+        public void Clear()
+        {
+            array = EmptyArray;
+            count = 0;
+        }
+
+        /// <summary>
+        /// Determines whether this collection contains the given item.
+        /// </summary>
+        /// <param name="item">The item to find.</param>
+        /// <returns><c>true</c> if this collection contains the given item; <c>false</c> otherwise.</returns>
+        public bool Contains(T item)
+        {
+            return IndexOf(item) != -1;
+        }
+
+        /// <summary>
+        /// Copies this collection to the given array.
+        /// </summary>
+        /// <param name="array">The array to copy to.</param>
+        /// <param name="arrayIndex">The first index of the array to copy to.</param>
+        public void CopyTo(T[] array, int arrayIndex)
+        {
+            Array.Copy(this.array, 0, array, arrayIndex, count);
+        }
+
+        /// <summary>
+        /// Removes the specified item from the collection
+        /// </summary>
+        /// <param name="item">The item to remove.</param>
+        /// <returns><c>true</c> if the item was found and removed; <c>false</c> otherwise.</returns>
+        public bool Remove(T item)
+        {
+            int index = IndexOf(item);
+            if (index == -1)
+            {
+                return false;
+            }
+            Array.Copy(array, index + 1, array, index, count - index - 1);
+            count--;
+            array[count] = default(T);
+            return true;
+        }
+
+        /// <summary>
+        /// Gets the number of elements contained in the collection.
+        /// </summary>
+        public int Count
+        {
+            get
+            {
+                return count;
+            }
+        }
+
+        /// <summary>
+        /// Gets a value indicating whether the collection is read-only.
+        /// </summary>
+        public bool IsReadOnly
+        {
+            get
+            {
+                return false;
+            }
+        }
+
+        /// <summary>
+        /// Adds all of the specified values into this collection.
+        /// </summary>
+        /// <param name="values">The values to add to this collection.</param>
+        public void AddRange(IEnumerable<T> values)
+        {
+            ProtoPreconditions.CheckNotNull(values, "values");
+
+            // Optimization 1: If the collection we're adding is already a RepeatedField<T>,
+            // we know the values are valid.
+            var otherRepeatedField = values as RepeatedField<T>;
+            if (otherRepeatedField != null)
+            {
+                EnsureSize(count + otherRepeatedField.count);
+                Array.Copy(otherRepeatedField.array, 0, array, count, otherRepeatedField.count);
+                count += otherRepeatedField.count;
+                return;
+            }
+
+            // Optimization 2: The collection is an ICollection, so we can expand
+            // just once and ask the collection to copy itself into the array.
+            var collection = values as ICollection;
+            if (collection != null)
+            {
+                var extraCount = collection.Count;
+                // For reference types and nullable value types, we need to check that there are no nulls
+                // present. (This isn't a thread-safe approach, but we don't advertise this is thread-safe.)
+                // We expect the JITter to optimize this test to true/false, so it's effectively conditional
+                // specialization.
+                if (default(T) == null)
+                {
+                    // TODO: Measure whether iterating once to check and then letting the collection copy
+                    // itself is faster or slower than iterating and adding as we go. For large
+                    // collections this will not be great in terms of cache usage... but the optimized
+                    // copy may be significantly faster than doing it one at a time.
+                    foreach (var item in collection)
+                    {
+                        if (item == null)
+                        {
+                            throw new ArgumentException("Sequence contained null element", "values");
+                        }
+                    }
+                }
+                EnsureSize(count + extraCount);
+                collection.CopyTo(array, count);
+                count += extraCount;
+                return;
+            }
+
+            // We *could* check for ICollection<T> as well, but very very few collections implement
+            // ICollection<T> but not ICollection. (HashSet<T> does, for one...)
+
+            // Fall back to a slower path of adding items one at a time.
+            foreach (T item in values)
+            {
+                Add(item);
+            }
+        }
+
+        /// <summary>
+        /// Adds all of the specified values into this collection. This method is present to
+        /// allow repeated fields to be constructed from queries within collection initializers.
+        /// Within non-collection-initializer code, consider using the equivalent <see cref="AddRange"/>
+        /// method instead for clarity.
+        /// </summary>
+        /// <param name="values">The values to add to this collection.</param>
+        public void Add(IEnumerable<T> values)
+        {
+            AddRange(values);
+        }
+
+        /// <summary>
+        /// Returns an enumerator that iterates through the collection.
+        /// </summary>
+        /// <returns>
+        /// An enumerator that can be used to iterate through the collection.
+        /// </returns>
+        public IEnumerator<T> GetEnumerator()
+        {
+            for (int i = 0; i < count; i++)
+            {
+                yield return array[i];
+            }
+        }
+
+        /// <summary>
+        /// Determines whether the specified <see cref="System.Object" />, is equal to this instance.
+        /// </summary>
+        /// <param name="obj">The <see cref="System.Object" /> to compare with this instance.</param>
+        /// <returns>
+        ///   <c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.
+        /// </returns>
+        public override bool Equals(object obj)
+        {
+            return Equals(obj as RepeatedField<T>);
+        }
+
+        /// <summary>
+        /// Returns an enumerator that iterates through a collection.
+        /// </summary>
+        /// <returns>
+        /// An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.
+        /// </returns>
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return GetEnumerator();
+        }
+
+        /// <summary>
+        /// Returns a hash code for this instance.
+        /// </summary>
+        /// <returns>
+        /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 
+        /// </returns>
+        public override int GetHashCode()
+        {
+            int hash = 0;
+            for (int i = 0; i < count; i++)
+            {
+                hash = hash * 31 + array[i].GetHashCode();
+            }
+            return hash;
+        }
+
+        /// <summary>
+        /// Compares this repeated field with another for equality.
+        /// </summary>
+        /// <param name="other">The repeated field to compare this with.</param>
+        /// <returns><c>true</c> if <paramref name="other"/> refers to an equal repeated field; <c>false</c> otherwise.</returns>
+        public bool Equals(RepeatedField<T> other)
+        {
+            if (ReferenceEquals(other, null))
+            {
+                return false;
+            }
+            if (ReferenceEquals(other, this))
+            {
+                return true;
+            }
+            if (other.Count != this.Count)
+            {
+                return false;
+            }
+            EqualityComparer<T> comparer = EqualityComparer<T>.Default;
+            for (int i = 0; i < count; i++)
+            {
+                if (!comparer.Equals(array[i], other.array[i]))
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        /// <summary>
+        /// Returns the index of the given item within the collection, or -1 if the item is not
+        /// present.
+        /// </summary>
+        /// <param name="item">The item to find in the collection.</param>
+        /// <returns>The zero-based index of the item, or -1 if it is not found.</returns>
+        public int IndexOf(T item)
+        {
+            ProtoPreconditions.CheckNotNullUnconstrained(item, "item");
+            EqualityComparer<T> comparer = EqualityComparer<T>.Default;
+            for (int i = 0; i < count; i++)
+            {
+                if (comparer.Equals(array[i], item))
+                {
+                    return i;
+                }
+            }
+            return -1;
+        }
+
+        /// <summary>
+        /// Inserts the given item at the specified index.
+        /// </summary>
+        /// <param name="index">The index at which to insert the item.</param>
+        /// <param name="item">The item to insert.</param>
+        public void Insert(int index, T item)
+        {
+            ProtoPreconditions.CheckNotNullUnconstrained(item, "item");
+            if (index < 0 || index > count)
+            {
+                throw new ArgumentOutOfRangeException("index");
+            }
+            EnsureSize(count + 1);
+            Array.Copy(array, index, array, index + 1, count - index);
+            array[index] = item;
+            count++;
+        }
+
+        /// <summary>
+        /// Removes the item at the given index.
+        /// </summary>
+        /// <param name="index">The zero-based index of the item to remove.</param>
+        public void RemoveAt(int index)
+        {
+            if (index < 0 || index >= count)
+            {
+                throw new ArgumentOutOfRangeException("index");
+            }
+            Array.Copy(array, index + 1, array, index, count - index - 1);
+            count--;
+            array[count] = default(T);
+        }
+
+        /// <summary>
+        /// Gets or sets the item at the specified index.
+        /// </summary>
+        /// <value>
+        /// The element at the specified index.
+        /// </value>
+        /// <param name="index">The zero-based index of the element to get or set.</param>
+        /// <returns>The item at the specified index.</returns>
+        public T this[int index]
+        {
+            get
+            {
+                if (index < 0 || index >= count)
+                {
+                    throw new ArgumentOutOfRangeException("index");
+                }
+                return array[index];
+            }
+            set
+            {
+                if (index < 0 || index >= count)
+                {
+                    throw new ArgumentOutOfRangeException("index");
+                }
+                ProtoPreconditions.CheckNotNullUnconstrained(value, "value");
+                array[index] = value;
+            }
+        }
+
+        #region Explicit interface implementation for IList and ICollection.
+        bool IList.IsFixedSize
+        {
+            get
+            {
+                return false;
+            }
+        }
+
+        void ICollection.CopyTo(Array array, int index)
+        {
+            Array.Copy(this.array, 0, array, index, count);
+        }
+
+        bool ICollection.IsSynchronized
+        {
+            get
+            {
+                return false;
+            }
+        }
+
+        object ICollection.SyncRoot
+        {
+            get
+            {
+                return this;
+            }
+        }
+
+        object IList.this[int index]
+        {
+            get { return this[index]; }
+            set { this[index] = (T)value; }
+        }
+
+        int IList.Add(object value)
+        {
+            Add((T)value);
+            return count - 1;
+        }
+
+        bool IList.Contains(object value)
+        {
+            return (value is T && Contains((T)value));
+        }
+
+        int IList.IndexOf(object value)
+        {
+            if (!(value is T))
+            {
+                return -1;
+            }
+            return IndexOf((T)value);
+        }
+
+        void IList.Insert(int index, object value)
+        {
+            Insert(index, (T)value);
+        }
+
+        void IList.Remove(object value)
+        {
+            if (!(value is T))
+            {
+                return;
+            }
+            Remove((T)value);
+        }
+        #endregion        
+    }
+}

+ 64 - 0
Server/ThirdParty/Google.Protobuf/Compatibility/PropertyInfoExtensions.cs

@@ -0,0 +1,64 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System.Reflection;
+
+namespace Google.Protobuf.Compatibility
+{
+    /// <summary>
+    /// Extension methods for <see cref="PropertyInfo"/>, effectively providing
+    /// the familiar members from previous desktop framework versions while
+    /// targeting the newer releases, .NET Core etc.
+    /// </summary>
+    internal static class PropertyInfoExtensions
+    {
+        /// <summary>
+        /// Returns the public getter of a property, or null if there is no such getter
+        /// (either because it's read-only, or the getter isn't public).
+        /// </summary>
+        internal static MethodInfo GetGetMethod(this PropertyInfo target)
+        {
+            var method = target.GetGetMethod();
+            return method != null && method.IsPublic ? method : null;
+        }
+
+        /// <summary>
+        /// Returns the public setter of a property, or null if there is no such setter
+        /// (either because it's write-only, or the setter isn't public).
+        /// </summary>
+        internal static MethodInfo GetSetMethod(this PropertyInfo target)
+        {
+            var method = target.GetSetMethod();
+            return method != null && method.IsPublic ? method : null;
+        }
+    }
+}

+ 64 - 0
Server/ThirdParty/Google.Protobuf/Compatibility/StreamExtensions.cs

@@ -0,0 +1,64 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.IO;
+
+namespace Google.Protobuf.Compatibility
+{
+    /// <summary>
+    /// Extension methods for <see cref="Stream"/> in order to provide
+    /// backwards compatibility with .NET 3.5
+    /// </summary>
+    public static class StreamExtensions
+    {
+        // 81920 seems to be the default buffer size used in .NET 4.5.1
+        private const int BUFFER_SIZE = 81920;
+
+        /// <summary>
+        /// Write the contents of the current stream to the destination stream
+        /// </summary>
+        public static void CopyTo(this Stream source, Stream destination)
+        {
+            if (destination == null)
+            {
+                throw new ArgumentNullException("destination");
+            }
+
+            byte[] buffer = new byte[BUFFER_SIZE];
+            int numBytesRead;
+            while ((numBytesRead = source.Read(buffer, 0, buffer.Length)) > 0) {
+                destination.Write(buffer, 0, numBytesRead);
+            }
+        }
+    }
+}

+ 379 - 0
Server/ThirdParty/Google.Protobuf/FieldCodec.cs

@@ -0,0 +1,379 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Factory methods for <see cref="FieldCodec{T}"/>.
+    /// </summary>
+    public static class FieldCodec
+    {
+        // TODO: Avoid the "dual hit" of lambda expressions: create open delegates instead. (At least test...)
+
+        /// <summary>
+        /// Retrieves a codec suitable for a string field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<string> ForString(uint tag)
+        {
+            return new FieldCodec<string>(input => input.ReadString(), (output, value) => output.WriteString(value), CodedOutputStream.ComputeStringSize, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a bytes field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<ByteString> ForBytes(uint tag)
+        {
+            return new FieldCodec<ByteString>(input => input.ReadBytes(), (output, value) => output.WriteBytes(value), CodedOutputStream.ComputeBytesSize, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a bool field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<bool> ForBool(uint tag)
+        {
+            return new FieldCodec<bool>(input => input.ReadBool(), (output, value) => output.WriteBool(value), CodedOutputStream.ComputeBoolSize, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for an int32 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<int> ForInt32(uint tag)
+        {
+            return new FieldCodec<int>(input => input.ReadInt32(), (output, value) => output.WriteInt32(value), CodedOutputStream.ComputeInt32Size, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for an sint32 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<int> ForSInt32(uint tag)
+        {
+            return new FieldCodec<int>(input => input.ReadSInt32(), (output, value) => output.WriteSInt32(value), CodedOutputStream.ComputeSInt32Size, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a fixed32 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<uint> ForFixed32(uint tag)
+        {
+            return new FieldCodec<uint>(input => input.ReadFixed32(), (output, value) => output.WriteFixed32(value), 4, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for an sfixed32 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<int> ForSFixed32(uint tag)
+        {
+            return new FieldCodec<int>(input => input.ReadSFixed32(), (output, value) => output.WriteSFixed32(value), 4, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a uint32 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<uint> ForUInt32(uint tag)
+        {
+            return new FieldCodec<uint>(input => input.ReadUInt32(), (output, value) => output.WriteUInt32(value), CodedOutputStream.ComputeUInt32Size, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for an int64 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<long> ForInt64(uint tag)
+        {
+            return new FieldCodec<long>(input => input.ReadInt64(), (output, value) => output.WriteInt64(value), CodedOutputStream.ComputeInt64Size, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for an sint64 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<long> ForSInt64(uint tag)
+        {
+            return new FieldCodec<long>(input => input.ReadSInt64(), (output, value) => output.WriteSInt64(value), CodedOutputStream.ComputeSInt64Size, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a fixed64 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<ulong> ForFixed64(uint tag)
+        {
+            return new FieldCodec<ulong>(input => input.ReadFixed64(), (output, value) => output.WriteFixed64(value), 8, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for an sfixed64 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<long> ForSFixed64(uint tag)
+        {
+            return new FieldCodec<long>(input => input.ReadSFixed64(), (output, value) => output.WriteSFixed64(value), 8, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a uint64 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<ulong> ForUInt64(uint tag)
+        {
+            return new FieldCodec<ulong>(input => input.ReadUInt64(), (output, value) => output.WriteUInt64(value), CodedOutputStream.ComputeUInt64Size, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a float field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<float> ForFloat(uint tag)
+        {
+            return new FieldCodec<float>(input => input.ReadFloat(), (output, value) => output.WriteFloat(value), CodedOutputStream.ComputeFloatSize, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a double field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<double> ForDouble(uint tag)
+        {
+            return new FieldCodec<double>(input => input.ReadDouble(), (output, value) => output.WriteDouble(value), CodedOutputStream.ComputeDoubleSize, tag);
+        }
+
+        // Enums are tricky. We can probably use expression trees to build these delegates automatically,
+        // but it's easy to generate the code for it.
+
+        /// <summary>
+        /// Retrieves a codec suitable for an enum field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <param name="toInt32">A conversion function from <see cref="Int32"/> to the enum type.</param>
+        /// <param name="fromInt32">A conversion function from the enum type to <see cref="Int32"/>.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<T> ForEnum<T>(uint tag, Func<T, int> toInt32, Func<int, T> fromInt32)
+        {
+            return new FieldCodec<T>(input => fromInt32(
+                input.ReadEnum()),
+                (output, value) => output.WriteEnum(toInt32(value)),
+                value => CodedOutputStream.ComputeEnumSize(toInt32(value)), tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a message field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <param name="parser">A parser to use for the message type.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<T> ForMessage<T>(uint tag, MessageParser<T> parser) where T : IMessage
+        {
+            return new FieldCodec<T>(input => { T message = parser.CreateTemplate(); input.ReadMessage(message); return message; },
+                (output, value) => output.WriteMessage(value), message => CodedOutputStream.ComputeMessageSize(message), tag);
+        }
+    }
+
+    /// <summary>
+    /// <para>
+    /// An encode/decode pair for a single field. This effectively encapsulates
+    /// all the information needed to read or write the field value from/to a coded
+    /// stream.
+    /// </para>
+    /// <para>
+    /// This class is public and has to be as it is used by generated code, but its public
+    /// API is very limited - just what the generated code needs to call directly.
+    /// </para>
+    /// </summary>
+    /// <remarks>
+    /// This never writes default values to the stream, and does not address "packedness"
+    /// in repeated fields itself, other than to know whether or not the field *should* be packed.
+    /// </remarks>
+    public sealed class FieldCodec<T>
+    {
+        private static readonly T DefaultDefault;
+        // Only non-nullable value types support packing. This is the simplest way of detecting that.
+        private static readonly bool TypeSupportsPacking = default(T) != null;
+
+        static FieldCodec()
+        {
+            if (typeof(T) == typeof(string))
+            {
+                DefaultDefault = (T)(object)"";
+            }
+            else if (typeof(T) == typeof(ByteString))
+            {
+                DefaultDefault = (T)(object)ByteString.Empty;
+            }
+            // Otherwise it's the default value of the CLR type
+        }
+
+        internal static bool IsPackedRepeatedField(uint tag)
+        {
+            return TypeSupportsPacking && WireFormat.GetTagWireType(tag) == WireFormat.WireType.LengthDelimited;
+        }
+
+        internal readonly bool PackedRepeatedField;
+
+        /// <summary>
+        /// Returns a delegate to write a value (unconditionally) to a coded output stream.
+        /// </summary>
+        internal readonly Action<CodedOutputStream, T> ValueWriter;
+
+        /// <summary>
+        /// Returns the size calculator for just a value.
+        /// </summary>
+        internal readonly Func<T, int> ValueSizeCalculator;
+
+        /// <summary>
+        /// Returns a delegate to read a value from a coded input stream. It is assumed that
+        /// the stream is already positioned on the appropriate tag.
+        /// </summary>
+        internal readonly Func<CodedInputStream, T> ValueReader;
+
+        /// <summary>
+        /// Returns the fixed size for an entry, or 0 if sizes vary.
+        /// </summary>
+        internal readonly int FixedSize;
+
+        /// <summary>
+        /// Gets the tag of the codec.
+        /// </summary>
+        /// <value>
+        /// The tag of the codec.
+        /// </value>
+        internal readonly uint Tag;
+
+        /// <summary>
+        /// Default value for this codec. Usually the same for every instance of the same type, but
+        /// for string/ByteString wrapper fields the codec's default value is null, whereas for
+        /// other string/ByteString fields it's "" or ByteString.Empty.
+        /// </summary>
+        /// <value>
+        /// The default value of the codec's type.
+        /// </value>
+        internal readonly T DefaultValue;
+
+        private readonly int tagSize;
+        
+        internal FieldCodec(
+                Func<CodedInputStream, T> reader,
+                Action<CodedOutputStream, T> writer,
+                int fixedSize,
+                uint tag) : this(reader, writer, _ => fixedSize, tag)
+        {
+            FixedSize = fixedSize;
+        }
+
+        internal FieldCodec(
+            Func<CodedInputStream, T> reader,
+            Action<CodedOutputStream, T> writer,
+            Func<T, int> sizeCalculator,
+            uint tag) : this(reader, writer, sizeCalculator, tag, DefaultDefault)
+        {
+        }
+
+        internal FieldCodec(
+            Func<CodedInputStream, T> reader,
+            Action<CodedOutputStream, T> writer,
+            Func<T, int> sizeCalculator,
+            uint tag,
+            T defaultValue)
+        {
+            ValueReader = reader;
+            ValueWriter = writer;
+            ValueSizeCalculator = sizeCalculator;
+            FixedSize = 0;
+            Tag = tag;
+            DefaultValue = defaultValue;
+            tagSize = CodedOutputStream.ComputeRawVarint32Size(tag);
+            // Detect packed-ness once, so we can check for it within RepeatedField<T>.
+            PackedRepeatedField = IsPackedRepeatedField(tag);
+        }
+
+        /// <summary>
+        /// Write a tag and the given value, *if* the value is not the default.
+        /// </summary>
+        public void WriteTagAndValue(CodedOutputStream output, T value)
+        {
+            if (!IsDefault(value))
+            {
+                output.WriteTag(Tag);
+                ValueWriter(output, value);
+            }
+        }
+
+        /// <summary>
+        /// Reads a value of the codec type from the given <see cref="CodedInputStream"/>.
+        /// </summary>
+        /// <param name="input">The input stream to read from.</param>
+        /// <returns>The value read from the stream.</returns>
+        public T Read(CodedInputStream input)
+        {
+            return ValueReader(input);
+        }
+
+        /// <summary>
+        /// Calculates the size required to write the given value, with a tag,
+        /// if the value is not the default.
+        /// </summary>
+        public int CalculateSizeWithTag(T value)
+        {
+            return IsDefault(value) ? 0 : ValueSizeCalculator(value) + tagSize;
+        }
+
+        private bool IsDefault(T value)
+        {
+            return EqualityComparer<T>.Default.Equals(value, DefaultValue);
+        }
+    }
+}

+ 11 - 0
Server/ThirdParty/Google.Protobuf/Google.Protobuf.csproj

@@ -0,0 +1,11 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>Library</OutputType>
+    <TargetFramework>netcoreapp2.1</TargetFramework>
+    <ApplicationIcon />
+    <StartupObject />
+  </PropertyGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\MongodbDriver\DotNetCoreDriver\MongoDB.Bson\MongoDB.Bson.csproj" />
+  </ItemGroup>
+</Project>

+ 69 - 0
Server/ThirdParty/Google.Protobuf/ICustomDiagnosticMessage.cs

@@ -0,0 +1,69 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2016 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// A message type that has a custom string format for diagnostic purposes.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// Calling <see cref="object.ToString"/> on a generated message type normally
+    /// returns the JSON representation. If a message type implements this interface,
+    /// then the <see cref="ToDiagnosticString"/> method will be called instead of the regular
+    /// JSON formatting code, but only when <c>ToString()</c> is called either on the message itself
+    /// or on another message which contains it. This does not affect the normal JSON formatting of
+    /// the message.
+    /// </para>
+    /// <para>
+    /// For example, if you create a proto message representing a GUID, the internal
+    /// representation may be a <c>bytes</c> field or four <c>fixed32</c> fields. However, when debugging
+    /// it may be more convenient to see a result in the same format as <see cref="System.Guid"/> provides.
+    /// </para>
+    /// <para>This interface extends <see cref="IMessage"/> to avoid it accidentally being implemented
+    /// on types other than messages, where it would not be used by anything in the framework.</para>
+    /// </remarks>
+    public interface ICustomDiagnosticMessage : IMessage
+    {
+        /// <summary>
+        /// Returns a string representation of this object, for diagnostic purposes.
+        /// </summary>
+        /// <remarks>
+        /// This method is called when a message is formatted as part of a <see cref="object.ToString"/>
+        /// call. It does not affect the JSON representation used by <see cref="JsonFormatter"/> other than
+        /// in calls to <see cref="JsonFormatter.ToDiagnosticString(IMessage)"/>. While it is recommended
+        /// that the result is valid JSON, this is never assumed by the Protobuf library.
+        /// </remarks>
+        /// <returns>A string representation of this object, for diagnostic purposes.</returns>
+        string ToDiagnosticString();
+    }
+}

+ 64 - 0
Server/ThirdParty/Google.Protobuf/IMessage.cs

@@ -0,0 +1,64 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Interface for a Protocol Buffers message, supporting
+    /// basic operations required for serialization.
+    /// </summary>
+    public interface IMessage
+    {
+        /// <summary>
+        /// Merges the data from the specified coded input stream with the current message.
+        /// </summary>
+        /// <remarks>See the user guide for precise merge semantics.</remarks>
+        /// <param name="input"></param>
+        void MergeFrom(CodedInputStream input);
+
+        /// <summary>
+        /// Writes the data to the given coded output stream.
+        /// </summary>
+        /// <param name="output">Coded output stream to write the data to. Must not be null.</param>
+        void WriteTo(CodedOutputStream output);
+
+        /// <summary>
+        /// Calculates the size of this message in Protocol Buffer wire format, in bytes.
+        /// </summary>
+        /// <returns>The number of bytes required to write this message
+        /// to a coded output stream.</returns>
+        int CalculateSize();
+
+    }
+
+}

+ 129 - 0
Server/ThirdParty/Google.Protobuf/InvalidProtocolBufferException.cs

@@ -0,0 +1,129 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.IO;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Thrown when a protocol message being parsed is invalid in some way,
+    /// e.g. it contains a malformed varint or a negative byte length.
+    /// </summary>
+    public sealed class InvalidProtocolBufferException : IOException
+    {
+        internal InvalidProtocolBufferException(string message)
+            : base(message)
+        {
+        }
+
+        internal InvalidProtocolBufferException(string message, Exception innerException)
+            : base(message, innerException)
+        {
+        }
+
+        internal static InvalidProtocolBufferException MoreDataAvailable()
+        {
+            return new InvalidProtocolBufferException(
+                "Completed reading a message while more data was available in the stream.");
+        }
+
+        internal static InvalidProtocolBufferException TruncatedMessage()
+        {
+            return new InvalidProtocolBufferException(
+                "While parsing a protocol message, the input ended unexpectedly " +
+                "in the middle of a field.  This could mean either that the " +
+                "input has been truncated or that an embedded message " +
+                "misreported its own length.");
+        }
+
+        internal static InvalidProtocolBufferException NegativeSize()
+        {
+            return new InvalidProtocolBufferException(
+                "CodedInputStream encountered an embedded string or message " +
+                "which claimed to have negative size.");
+        }
+
+        internal static InvalidProtocolBufferException MalformedVarint()
+        {
+            return new InvalidProtocolBufferException(
+                "CodedInputStream encountered a malformed varint.");
+        }
+
+        /// <summary>
+        /// Creates an exception for an error condition of an invalid tag being encountered.
+        /// </summary>
+        internal static InvalidProtocolBufferException InvalidTag()
+        {
+            return new InvalidProtocolBufferException(
+                "Protocol message contained an invalid tag (zero).");
+        }
+
+        internal static InvalidProtocolBufferException InvalidBase64(Exception innerException)
+        {
+            return new InvalidProtocolBufferException("Invalid base64 data", innerException);
+        }
+
+        internal static InvalidProtocolBufferException InvalidEndTag()
+        {
+            return new InvalidProtocolBufferException(
+                "Protocol message end-group tag did not match expected tag.");
+        }
+
+        internal static InvalidProtocolBufferException RecursionLimitExceeded()
+        {
+            return new InvalidProtocolBufferException(
+                "Protocol message had too many levels of nesting.  May be malicious.  " +
+                "Use CodedInputStream.SetRecursionLimit() to increase the depth limit.");
+        }
+
+        internal static InvalidProtocolBufferException JsonRecursionLimitExceeded()
+        {
+            return new InvalidProtocolBufferException(
+                "Protocol message had too many levels of nesting.  May be malicious.  " +
+                "Use JsonParser.Settings to increase the depth limit.");
+        }
+
+        internal static InvalidProtocolBufferException SizeLimitExceeded()
+        {
+            return new InvalidProtocolBufferException(
+                "Protocol message was too large.  May be malicious.  " +
+                "Use CodedInputStream.SetSizeLimit() to increase the size limit.");
+        }
+
+        internal static InvalidProtocolBufferException InvalidMessageStreamTag()
+        {
+            return new InvalidProtocolBufferException(
+                "Stream of protocol messages had invalid tag. Expected tag is length-delimited field 1.");
+        }
+    }
+}

+ 110 - 0
Server/ThirdParty/Google.Protobuf/LimitedInputStream.cs

@@ -0,0 +1,110 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+    
+using System;
+using System.IO;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Stream implementation which proxies another stream, only allowing a certain amount
+    /// of data to be read. Note that this is only used to read delimited streams, so it
+    /// doesn't attempt to implement everything.
+    /// </summary>
+    internal sealed class LimitedInputStream : Stream
+    {
+        private readonly Stream proxied;
+        private int bytesLeft;
+
+        internal LimitedInputStream(Stream proxied, int size)
+        {
+            this.proxied = proxied;
+            bytesLeft = size;
+        }
+
+        public override bool CanRead
+        {
+            get { return true; }
+        }
+
+        public override bool CanSeek
+        {
+            get { return false; }
+        }
+
+        public override bool CanWrite
+        {
+            get { return false; }
+        }
+
+        public override void Flush()
+        {
+        }
+
+        public override long Length
+        {
+            get { throw new NotSupportedException(); }
+        }
+
+        public override long Position
+        {
+            get { throw new NotSupportedException(); }
+            set { throw new NotSupportedException(); }
+        }
+
+        public override int Read(byte[] buffer, int offset, int count)
+        {
+            if (bytesLeft > 0)
+            {
+                int bytesRead = proxied.Read(buffer, offset, Math.Min(bytesLeft, count));
+                bytesLeft -= bytesRead;
+                return bytesRead;
+            }
+            return 0;
+        }
+
+        public override long Seek(long offset, SeekOrigin origin)
+        {
+            throw new NotSupportedException();
+        }
+
+        public override void SetLength(long value)
+        {
+            throw new NotSupportedException();
+        }
+
+        public override void Write(byte[] buffer, int offset, int count)
+        {
+            throw new NotSupportedException();
+        }
+    }
+}

+ 171 - 0
Server/ThirdParty/Google.Protobuf/MessageExtensions.cs

@@ -0,0 +1,171 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System.IO;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Extension methods on <see cref="IMessage"/> and <see cref="IMessage{T}"/>.
+    /// </summary>
+    public static class MessageExtensions
+    {
+        /// <summary>
+        /// Merges data from the given byte array into an existing message.
+        /// </summary>
+        /// <param name="message">The message to merge the data into.</param>
+        /// <param name="data">The data to merge, which must be protobuf-encoded binary data.</param>
+        public static void MergeFrom(this IMessage message, byte[] data)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(data, "data");
+            CodedInputStream input = new CodedInputStream(data);
+            message.MergeFrom(input);
+            input.CheckReadEndOfStreamTag();
+        }
+
+	    /// <summary>
+	    /// Merges data from the given byte array into an existing message.
+	    /// </summary>
+	    /// <param name="message">The message to merge the data into.</param>
+	    /// <param name="data">The data to merge, which must be protobuf-encoded binary data.</param>
+	    public static void MergeFrom(this IMessage message, byte[] data, int offset, int length)
+	    {
+		    ProtoPreconditions.CheckNotNull(message, "message");
+		    ProtoPreconditions.CheckNotNull(data, "data");
+		    CodedInputStream input = new CodedInputStream(data, offset, length);
+		    message.MergeFrom(input);
+		    input.CheckReadEndOfStreamTag();
+	    }
+
+		/// <summary>
+		/// Merges data from the given byte string into an existing message.
+		/// </summary>
+		/// <param name="message">The message to merge the data into.</param>
+		/// <param name="data">The data to merge, which must be protobuf-encoded binary data.</param>
+		public static void MergeFrom(this IMessage message, ByteString data)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(data, "data");
+            CodedInputStream input = data.CreateCodedInput();
+            message.MergeFrom(input);
+            input.CheckReadEndOfStreamTag();
+        }
+
+        /// <summary>
+        /// Merges data from the given stream into an existing message.
+        /// </summary>
+        /// <param name="message">The message to merge the data into.</param>
+        /// <param name="input">Stream containing the data to merge, which must be protobuf-encoded binary data.</param>
+        public static void MergeFrom(this IMessage message, Stream input)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(input, "input");
+            CodedInputStream codedInput = new CodedInputStream(input);
+            message.MergeFrom(codedInput);
+            codedInput.CheckReadEndOfStreamTag();
+        }
+
+        /// <summary>
+        /// Merges length-delimited data from the given stream into an existing message.
+        /// </summary>
+        /// <remarks>
+        /// The stream is expected to contain a length and then the data. Only the amount of data
+        /// specified by the length will be consumed.
+        /// </remarks>
+        /// <param name="message">The message to merge the data into.</param>
+        /// <param name="input">Stream containing the data to merge, which must be protobuf-encoded binary data.</param>
+        public static void MergeDelimitedFrom(this IMessage message, Stream input)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(input, "input");
+            int size = (int) CodedInputStream.ReadRawVarint32(input);
+            Stream limitedStream = new LimitedInputStream(input, size);
+            message.MergeFrom(limitedStream);
+        }
+
+        /// <summary>
+        /// Converts the given message into a byte array in protobuf encoding.
+        /// </summary>
+        /// <param name="message">The message to convert.</param>
+        /// <returns>The message data as a byte array.</returns>
+        public static byte[] ToByteArray(this IMessage message)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            byte[] result = new byte[message.CalculateSize()];
+            CodedOutputStream output = new CodedOutputStream(result);
+            message.WriteTo(output);
+            output.CheckNoSpaceLeft();
+            return result;
+        }
+
+        /// <summary>
+        /// Writes the given message data to the given stream in protobuf encoding.
+        /// </summary>
+        /// <param name="message">The message to write to the stream.</param>
+        /// <param name="output">The stream to write to.</param>
+        public static void WriteTo(this IMessage message, Stream output)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(output, "output");
+            CodedOutputStream codedOutput = new CodedOutputStream(output);
+            message.WriteTo(codedOutput);
+            codedOutput.Flush();
+        }
+
+        /// <summary>
+        /// Writes the length and then data of the given message to a stream.
+        /// </summary>
+        /// <param name="message">The message to write.</param>
+        /// <param name="output">The output stream to write to.</param>
+        public static void WriteDelimitedTo(this IMessage message, Stream output)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(output, "output");
+            CodedOutputStream codedOutput = new CodedOutputStream(output);
+            codedOutput.WriteRawVarint32((uint)message.CalculateSize());
+            message.WriteTo(codedOutput);
+            codedOutput.Flush();
+        }
+
+        /// <summary>
+        /// Converts the given message into a byte string in protobuf encoding.
+        /// </summary>
+        /// <param name="message">The message to convert.</param>
+        /// <returns>The message data as a byte string.</returns>
+        public static ByteString ToByteString(this IMessage message)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            return ByteString.AttachBytes(message.ToByteArray());
+        }        
+    }
+}

+ 241 - 0
Server/ThirdParty/Google.Protobuf/MessageParser.cs

@@ -0,0 +1,241 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+    
+using System;
+using System.IO;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// A general message parser, typically used by reflection-based code as all the methods
+    /// return simple <see cref="IMessage"/>.
+    /// </summary>
+    public class MessageParser
+    {
+        private Func<IMessage> factory;
+
+        internal MessageParser(Func<IMessage> factory)
+        {
+            this.factory = factory;
+        }
+
+        /// <summary>
+        /// Creates a template instance ready for population.
+        /// </summary>
+        /// <returns>An empty message.</returns>
+        internal IMessage CreateTemplate()
+        {
+            return factory();
+        }
+
+        /// <summary>
+        /// Parses a message from a byte array.
+        /// </summary>
+        /// <param name="data">The byte array containing the message. Must not be null.</param>
+        /// <returns>The newly parsed message.</returns>
+        public IMessage ParseFrom(byte[] data)
+        {
+            ProtoPreconditions.CheckNotNull(data, "data");
+            IMessage message = factory();
+            message.MergeFrom(data);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a message from the given byte string.
+        /// </summary>
+        /// <param name="data">The data to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public IMessage ParseFrom(ByteString data)
+        {
+            ProtoPreconditions.CheckNotNull(data, "data");
+            IMessage message = factory();
+            message.MergeFrom(data);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a message from the given stream.
+        /// </summary>
+        /// <param name="input">The stream to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public IMessage ParseFrom(Stream input)
+        {
+            IMessage message = factory();
+            message.MergeFrom(input);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a length-delimited message from the given stream.
+        /// </summary>
+        /// <remarks>
+        /// The stream is expected to contain a length and then the data. Only the amount of data
+        /// specified by the length will be consumed.
+        /// </remarks>
+        /// <param name="input">The stream to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public IMessage ParseDelimitedFrom(Stream input)
+        {
+            IMessage message = factory();
+            message.MergeDelimitedFrom(input);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a message from the given coded input stream.
+        /// </summary>
+        /// <param name="input">The stream to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public IMessage ParseFrom(CodedInputStream input)
+        {
+            IMessage message = factory();
+            message.MergeFrom(input);
+            return message;
+        }
+
+    }
+
+    /// <summary>
+    /// A parser for a specific message type.
+    /// </summary>
+    /// <remarks>
+    /// <p>
+    /// This delegates most behavior to the
+    /// <see cref="IMessage.MergeFrom"/> implementation within the original type, but
+    /// provides convenient overloads to parse from a variety of sources.
+    /// </p>
+    /// <p>
+    /// Most applications will never need to create their own instances of this type;
+    /// instead, use the static <c>Parser</c> property of a generated message type to obtain a
+    /// parser for that type.
+    /// </p>
+    /// </remarks>
+    /// <typeparam name="T">The type of message to be parsed.</typeparam>
+    public sealed class MessageParser<T> : MessageParser where T : IMessage
+    {
+        // Implementation note: all the methods here *could* just delegate up to the base class and cast the result.
+        // The current implementation avoids a virtual method call and a cast, which *may* be significant in some cases.
+        // Benchmarking work is required to measure the significance - but it's only a few lines of code in any case.
+        // The API wouldn't change anyway - just the implementation - so this work can be deferred.
+        private readonly Func<T> factory; 
+
+        /// <summary>
+        /// Creates a new parser.
+        /// </summary>
+        /// <remarks>
+        /// The factory method is effectively an optimization over using a generic constraint
+        /// to require a parameterless constructor: delegates are significantly faster to execute.
+        /// </remarks>
+        /// <param name="factory">Function to invoke when a new, empty message is required.</param>
+        public MessageParser(Func<T> factory) : base(() => factory())
+        {
+            this.factory = factory;
+        }
+
+        /// <summary>
+        /// Creates a template instance ready for population.
+        /// </summary>
+        /// <returns>An empty message.</returns>
+        internal new T CreateTemplate()
+        {
+            return factory();
+        }
+
+        /// <summary>
+        /// Parses a message from a byte array.
+        /// </summary>
+        /// <param name="data">The byte array containing the message. Must not be null.</param>
+        /// <returns>The newly parsed message.</returns>
+        public new T ParseFrom(byte[] data)
+        {
+            ProtoPreconditions.CheckNotNull(data, "data");
+            T message = factory();
+            message.MergeFrom(data);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a message from the given byte string.
+        /// </summary>
+        /// <param name="data">The data to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public new T ParseFrom(ByteString data)
+        {
+            ProtoPreconditions.CheckNotNull(data, "data");
+            T message = factory();
+            message.MergeFrom(data);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a message from the given stream.
+        /// </summary>
+        /// <param name="input">The stream to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public new T ParseFrom(Stream input)
+        {
+            T message = factory();
+            message.MergeFrom(input);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a length-delimited message from the given stream.
+        /// </summary>
+        /// <remarks>
+        /// The stream is expected to contain a length and then the data. Only the amount of data
+        /// specified by the length will be consumed.
+        /// </remarks>
+        /// <param name="input">The stream to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public new T ParseDelimitedFrom(Stream input)
+        {
+            T message = factory();
+            message.MergeDelimitedFrom(input);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a message from the given coded input stream.
+        /// </summary>
+        /// <param name="input">The stream to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public new T ParseFrom(CodedInputStream input)
+        {
+            T message = factory();
+            message.MergeFrom(input);
+            return message;
+        }
+
+    }
+}

+ 12 - 0
Server/ThirdParty/Google.Protobuf/Program.cs

@@ -0,0 +1,12 @@
+using System;
+
+namespace Google.Protobuf
+{
+    class Program
+    {
+        static void Main(string[] args)
+        {
+            Console.WriteLine("Hello World!");
+        }
+    }
+}

+ 79 - 0
Server/ThirdParty/Google.Protobuf/ProtoPreconditions.cs

@@ -0,0 +1,79 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Helper methods for throwing exceptions when preconditions are not met.
+    /// </summary>
+    /// <remarks>
+    /// This class is used internally and by generated code; it is not particularly
+    /// expected to be used from application code, although nothing prevents it
+    /// from being used that way.
+    /// </remarks>
+    public static class ProtoPreconditions
+    {
+        /// <summary>
+        /// Throws an ArgumentNullException if the given value is null, otherwise
+        /// return the value to the caller.
+        /// </summary>
+        public static T CheckNotNull<T>(T value, string name) where T : class
+        {
+            if (value == null)
+            {
+                throw new ArgumentNullException(name);
+            }
+            return value;
+        }
+
+        /// <summary>
+        /// Throws an ArgumentNullException if the given value is null, otherwise
+        /// return the value to the caller.
+        /// </summary>
+        /// <remarks>
+        /// This is equivalent to <see cref="CheckNotNull{T}(T, string)"/> but without the type parameter
+        /// constraint. In most cases, the constraint is useful to prevent you from calling CheckNotNull
+        /// with a value type - but it gets in the way if either you want to use it with a nullable
+        /// value type, or you want to use it with an unconstrained type parameter.
+        /// </remarks>
+        internal static T CheckNotNullUnconstrained<T>(T value, string name)
+        {
+            if (value == null)
+            {
+                throw new ArgumentNullException(name);
+            }
+            return value;
+        }
+    }
+}

+ 104 - 0
Server/ThirdParty/Google.Protobuf/WireFormat.cs

@@ -0,0 +1,104 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// This class is used internally by the Protocol Buffer Library and generated
+    /// message implementations. It is public only for the sake of those generated
+    /// messages. Others should not use this class directly.
+    /// <para>
+    /// This class contains constants and helper functions useful for dealing with
+    /// the Protocol Buffer wire format.
+    /// </para>
+    /// </summary>
+    public static class WireFormat
+    {
+        /// <summary>
+        /// Wire types within protobuf encoding.
+        /// </summary>
+        public enum WireType : uint
+        {
+            /// <summary>
+            /// Variable-length integer.
+            /// </summary>
+            Varint = 0,
+            /// <summary>
+            /// A fixed-length 64-bit value.
+            /// </summary>
+            Fixed64 = 1,
+            /// <summary>
+            /// A length-delimited value, i.e. a length followed by that many bytes of data.
+            /// </summary>
+            LengthDelimited = 2,
+            /// <summary>
+            /// A "start group" value - not supported by this implementation.
+            /// </summary>
+            StartGroup = 3,
+            /// <summary>
+            /// An "end group" value - not supported by this implementation.
+            /// </summary>
+            EndGroup = 4,
+            /// <summary>
+            /// A fixed-length 32-bit value.
+            /// </summary>
+            Fixed32 = 5
+        }
+        
+        private const int TagTypeBits = 3;
+        private const uint TagTypeMask = (1 << TagTypeBits) - 1;
+
+        /// <summary>
+        /// Given a tag value, determines the wire type (lower 3 bits).
+        /// </summary>
+        public static WireType GetTagWireType(uint tag)
+        {
+            return (WireType) (tag & TagTypeMask);
+        }
+
+        /// <summary>
+        /// Given a tag value, determines the field number (the upper 29 bits).
+        /// </summary>
+        public static int GetTagFieldNumber(uint tag)
+        {
+            return (int) tag >> TagTypeBits;
+        }
+
+        /// <summary>
+        /// Makes a tag value given a field number and wire type.
+        /// </summary>
+        public static uint MakeTag(int fieldNumber, WireType wireType)
+        {
+            return (uint) (fieldNumber << TagTypeBits) | (uint) wireType;
+        }        
+    }
+}

+ 38 - 233
Unity/Assets/Editor/Proto2CsEditor/Proto2CSEditor.cs

@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.Diagnostics;
 using System.IO;
 using System.Text;
 using ETModel;
@@ -12,69 +13,63 @@ namespace ETEditor
 		public string Name;
 		public int Opcode;
 	}
-
-	[Flags]
-	public enum HeadFlag
-	{
-		None = 0,
-		Bson = 1,
-		Proto = 2,
-	}
 	
 	public class Proto2CSEditor : EditorWindow
 	{
 		private const string protoPath = "../Proto/";
-		private const string serverMessagePath = "../Server/Hotfix/Module/Message/";
 		private const string clientMessagePath = "Assets/Scripts/Module/Message/";
 		private const string hotfixMessagePath = "Hotfix/Module/Message/";
 		private static readonly char[] splitChars = { ' ', '\t' };
 		private static readonly List<OpcodeInfo> msgOpcode = new List<OpcodeInfo>();
-		private static MultiMap<string, string> parentMsg = new MultiMap<string, string>();
 		
 		[MenuItem("Tools/Proto2CS")]
 		public static void AllProto2CS()
 		{
 			msgOpcode.Clear();
-			Proto2CS("ETModel", "OuterMessage.proto", clientMessagePath, "OuterOpcode", 100, HeadFlag.Proto);
-			GenerateOpcode("ETModel", "OuterOpcode", clientMessagePath);
-
-			Proto2CS("ETHotfix", "OuterMessage.proto", serverMessagePath, "OuterOpcode", 100, HeadFlag.Proto | HeadFlag.Bson, false);
-			GenerateOpcode("ETHotfix", "OuterOpcode", serverMessagePath);
-
-			msgOpcode.Clear();
-			Proto2CS("ETHotfix", "HotfixMessage.proto", hotfixMessagePath, "HotfixOpcode", 10000, HeadFlag.None);
-			GenerateOpcode("ETHotfix", "HotfixOpcode", hotfixMessagePath);
-
-			msgOpcode.Clear();
-			Proto2CS("ETHotfix", "HotfixMessage.proto", serverMessagePath, "HotfixOpcode", 10000, HeadFlag.Bson, false);
-			GenerateOpcode("ETHotfix", "HotfixOpcode", serverMessagePath);
+			Proto2CS("ETModel", "OuterMessage.proto", clientMessagePath, "OuterOpcode", 100);
+			
 
 			msgOpcode.Clear();
-			Proto2CS("ETHotfix", "InnerMessage.proto", serverMessagePath, "InnerOpcode", 1000, HeadFlag.Bson, false);
-			GenerateOpcode("ETHotfix", "InnerOpcode", serverMessagePath);
+			Proto2CS("ETHotfix", "HotfixMessage.proto", hotfixMessagePath, "HotfixOpcode", 10000);
 
 			AssetDatabase.Refresh();
 		}
+
+		public static void CommandRun(string exe, string arguments)
+		{
+			try
+			{
+				ProcessStartInfo info = new ProcessStartInfo
+				{
+					FileName = exe, 
+					Arguments = arguments, 
+					UseShellExecute = true,
+					WorkingDirectory = "."
+				};
+				Process.Start(info);
+			}
+			catch (Exception e)
+			{
+				Log.Error(e);
+			}
+		}
 		
-		public static void Proto2CS(string ns, string protoName, string outputPath, string opcodeClassName, int startOpcode, HeadFlag flag, bool isClient = true)
+		public static void Proto2CS(string ns, string protoName, string outputPath, string opcodeClassName, int startOpcode, bool isClient = true)
 		{
 			msgOpcode.Clear();
-			parentMsg = new MultiMap<string, string>();
 			string proto = Path.Combine(protoPath, protoName);
-			string csPath = Path.Combine(outputPath, Path.GetFileNameWithoutExtension(proto) + ".cs");
+			
+			CommandRun($"protoc.exe", $"--csharp_out=\"{outputPath}\" --proto_path=\"{protoPath}\" {protoName}");
 
 			string s = File.ReadAllText(proto);
 
 			StringBuilder sb = new StringBuilder();
-			sb.Append("using ProtoBuf;\n");
 			sb.Append("using ETModel;\n");
-			sb.Append("using System.Collections.Generic;\n");
-			sb.Append("using MongoDB.Bson.Serialization.Attributes;\n");
 			sb.Append($"namespace {ns}\n");
 			sb.Append("{\n");
 
 			bool isMsgStart = false;
-			string parentClass = "";
+
 			foreach (string line in s.Split('\n'))
 			{
 				string newline = line.Trim();
@@ -91,7 +86,7 @@ namespace ETEditor
 
 				if (newline.StartsWith("message"))
 				{
-					parentClass = "";
+					string parentClass = "";
 					isMsgStart = true;
 					string msgName = newline.Split(splitChars, StringSplitOptions.RemoveEmptyEntries)[1];
 					string[] ss = newline.Split(new []{"//"}, StringSplitOptions.RemoveEmptyEntries);
@@ -100,138 +95,35 @@ namespace ETEditor
 					{
 						parentClass = ss[1].Trim();
 					}
-
-					msgOpcode.Add(new OpcodeInfo() { Name = msgName, Opcode = ++startOpcode});
-					
-					sb.Append($"\t[Message({opcodeClassName}.{msgName})]\n");
-					sb.Append($"\t[ProtoContract]\n");
-					sb.Append($"\tpublic partial class {msgName}");
-					if (parentClass == "IActorMessage" || parentClass == "IActorRequest" || parentClass == "IActorResponse" || parentClass == "IFrameMessage")
-					{
-						sb.Append($": {parentClass}\n");
-					}
-					else if (parentClass != "")
-					{
-						sb.Append($": {parentClass}\n");
-					}
 					else
 					{
-						sb.Append("\n");
+						parentClass = "";
 					}
-				}
 
-				if (isMsgStart && newline == "{")
-				{
-					sb.Append("\t{\n");
+					msgOpcode.Add(new OpcodeInfo() { Name = msgName, Opcode = ++startOpcode});
 					
-					if (parentClass == "IRequest" || parentClass == "IActorRequest" || parentClass == "IActorMessage" || parentClass == "IFrameMessage")
-					{
-						sb.AppendLine("\t\t[ProtoMember(90, IsRequired = true)]");
-						sb.AppendLine("\t\tpublic int RpcId { get; set; }\n");
-					}
-
-					if (parentClass == "IResponse" || parentClass == "IActorResponse")
-					{
-						sb.AppendLine("\t\t[ProtoMember(90, IsRequired = true)]");
-						sb.AppendLine("\t\tpublic int RpcId { get; set; }\n");
-						sb.AppendLine("\t\t[ProtoMember(91, IsRequired = true)]");
-						sb.AppendLine("\t\tpublic int Error { get; set; }\n");
-						sb.AppendLine("\t\t[ProtoMember(92, IsRequired = true)]");
-						sb.AppendLine("\t\tpublic string Message { get; set; }\n");
-					}
-
-					if (parentClass == "IActorRequest" || parentClass == "IActorMessage")
-					{
-						sb.AppendLine("\t\t[ProtoMember(93, IsRequired = true)]");
-						sb.AppendLine("\t\tpublic long ActorId { get; set; }\n");
-					}
-
-					if (parentClass == "IFrameMessage")
+					sb.Append($"\t[Message({opcodeClassName}.{msgName})]\n");
+					sb.Append($"\tpublic partial class {msgName} ");
+					if (parentClass != "")
 					{
-						sb.AppendLine("\t\t[ProtoMember(94, IsRequired = true)]");
-						sb.AppendLine("\t\tpublic long Id { get; set; }\n");
+						sb.Append($": {parentClass} ");
 					}
-				}
 
-				// 成员
-				if (newline.StartsWith("required"))
-				{
-					Members(sb, newline, true);
-				}
-
-				if (newline.StartsWith("optional"))
-				{
-					Members(sb, newline, false);
+					sb.Append("{}\n\n");
 				}
-
-				if (newline.StartsWith("repeated"))
-				{
-					Repeated(sb, ns, newline, isClient);
-				}
-
+				
 				if (isMsgStart && newline == "}")
 				{
 					isMsgStart = false;
-					sb.Append("\t}\n\n");
 				}
 			}
 			sb.Append("}\n");
 
-			//if (!isClient)
-			//{
-				//GenerateHead(sb, ns, flag, opcodeClassName);
-			//}
-
-			File.WriteAllText(csPath, sb.ToString());
-		}
-
-		private static void GenerateHead(StringBuilder sb, string ns, HeadFlag flag, string opcodeClassName)
-		{
-			if ((flag & HeadFlag.Bson) != 0)
-			{
-				if (parentMsg.Count > 0)
-				{
-					sb.AppendLine($"namespace {ns}");
-					sb.AppendLine("{");
-					foreach (string parentClass in parentMsg.GetDictionary().Keys)
-					{
-						foreach (string s in parentMsg.GetAll(parentClass))
-						{
-							sb.Append($"\t[BsonKnownTypes(typeof({s}))]\n");
-						}
-
-						sb.Append($"\tpublic partial class {parentClass} {{}}\n\n");
-					}
-
-					sb.AppendLine("}");
-				}
-			}
-
-			if ((flag & HeadFlag.Proto) != 0)
-			{
-				if (parentMsg.Count > 0)
-				{
-					sb.AppendLine($"namespace {ns}");
-					sb.AppendLine("{");
-					foreach (string parentClass in parentMsg.GetDictionary().Keys)
-					{
-
-						foreach (string s in parentMsg.GetAll(parentClass))
-						{
-							sb.Append($"\t[ProtoInclude({opcodeClassName}.{s}, typeof({s}))]\n");
-						}
-
-						sb.Append($"\tpublic partial class {parentClass} {{}}\n\n");
-					}
-
-					sb.AppendLine("}");
-				}
-			}
+			GenerateOpcode(ns, opcodeClassName, outputPath, sb);
 		}
 		
-		private static void GenerateOpcode(string ns, string outputFileName, string outputPath)
+		private static void GenerateOpcode(string ns, string outputFileName, string outputPath, StringBuilder sb)
 		{
-			StringBuilder sb = new StringBuilder();
 			sb.AppendLine($"namespace {ns}");
 			sb.AppendLine("{");
 			sb.AppendLine($"\tpublic static partial class {outputFileName}");
@@ -246,92 +138,5 @@ namespace ETEditor
 			string csPath = Path.Combine(outputPath, outputFileName + ".cs");
 			File.WriteAllText(csPath, sb.ToString());
 		}
-
-		private static void Repeated(StringBuilder sb, string ns, string newline, bool isClient)
-		{
-			try
-			{
-				int index = newline.IndexOf(";");
-				newline = newline.Remove(index);
-				string[] ss = newline.Split(splitChars, StringSplitOptions.RemoveEmptyEntries);
-				string type = ss[1];
-				type = ConvertType(type);
-				string name = ss[2];
-				int order = int.Parse(ss[4]);
-				if (isClient)
-				{
-					sb.Append($"\t\t[ProtoMember({order}, TypeName = \"{ns}.{type}\")]\n");
-				}
-				else
-				{
-					sb.Append($"\t\t[ProtoMember({order})]\n");
-				}
-
-				sb.Append($"\t\tpublic List<{type}> {name} = new List<{type}>();\n\n");
-			}
-			catch (Exception e)
-			{
-				Log.Error($"{newline}\n {e}");
-			}
-
-		}
-
-		private static string ConvertType(string type)
-		{
-			string typeCs = "";
-			switch (type)
-			{
-				case "int16":
-					typeCs = "short";
-					break;
-				case "int32":
-					typeCs = "int";
-					break;
-				case "bytes":
-					typeCs = "byte[]";
-					break;
-				case "uint32":
-					typeCs = "uint";
-					break;
-				case "long":
-					typeCs = "long";
-					break;
-				case "int64":
-					typeCs = "long";
-					break;
-				case "uint64":
-					typeCs = "ulong";
-					break;
-				case "uint16":
-					typeCs = "ushort";
-					break;
-				default:
-					typeCs = type;
-					break;
-			}
-			return typeCs;
-		}
-
-		private static void Members(StringBuilder sb, string newline, bool isRequired)
-		{
-			try
-			{
-				int index = newline.IndexOf(";");
-				newline = newline.Remove(index);
-				string[] ss = newline.Split(splitChars, StringSplitOptions.RemoveEmptyEntries);
-				string type = ss[1];
-				string name = ss[2];
-				int order = int.Parse(ss[4]);
-				sb.Append($"\t\t[ProtoMember({order}, IsRequired = {isRequired.ToString().ToLower()})]\n");
-				string typeCs = ConvertType(type);
-
-				sb.Append($"\t\tpublic {typeCs} {name};\n\n");
-			}
-			catch (Exception e)
-			{
-				Log.Error($"{newline}\n {e}");
-			}
-
-		}
 	}
 }

+ 0 - 98
Unity/Assets/Scripts/Base/Helper/ProtobufHelper.cs

@@ -1,98 +0,0 @@
-using System;
-using System.ComponentModel;
-using System.IO;
-using Microsoft.IO;
-using ProtoBuf;
-
-namespace ETModel
-{
-	public static class ProtobufHelper
-	{
-		private static readonly RecyclableMemoryStreamManager recyclableMemoryStreamManager = new RecyclableMemoryStreamManager();
-
-		public static byte[] ToBytes(object message)
-		{
-			using (MemoryStream ms = new MemoryStream())
-			{
-				Serializer.Serialize(ms, message);
-				return ms.ToArray();
-			}
-		}
-
-		public static T FromBytes<T>(byte[] bytes)
-		{
-			T t;
-			using (MemoryStream ms = recyclableMemoryStreamManager.GetStream("protobuf", bytes, 0, bytes.Length))
-			{
-				t = Serializer.Deserialize<T>(ms);
-			}
-			ISupportInitialize iSupportInitialize = t as ISupportInitialize;
-			if (iSupportInitialize == null)
-			{
-				return t;
-			}
-			iSupportInitialize.EndInit();
-			return t;
-		}
-
-		public static T FromBytes<T>(byte[] bytes, int index, int length)
-		{
-			T t;
-			using (MemoryStream ms = recyclableMemoryStreamManager.GetStream("protobuf", bytes, index, length))
-			{
-				t = Serializer.Deserialize<T>(ms);
-			}
-			ISupportInitialize iSupportInitialize = t as ISupportInitialize;
-			if (iSupportInitialize == null)
-			{
-				return t;
-			}
-			iSupportInitialize.EndInit();
-			return t;
-		}
-
-		public static object FromBytes(Type type, byte[] bytes)
-		{
-			object t;
-			using (MemoryStream ms = recyclableMemoryStreamManager.GetStream("protobuf", bytes, 0, bytes.Length))
-			{
-				t = Serializer.NonGeneric.Deserialize(type, ms);
-			}
-			ISupportInitialize iSupportInitialize = t as ISupportInitialize;
-			if (iSupportInitialize == null)
-			{
-				return t;
-			}
-			iSupportInitialize.EndInit();
-			return t;
-		}
-
-		public static object FromBytes(Type type, byte[] bytes, int index, int length)
-		{
-			object t;
-			using (MemoryStream ms = recyclableMemoryStreamManager.GetStream("protobuf", bytes, index, length))
-			{
-				t = Serializer.NonGeneric.Deserialize(type, ms);
-			}
-			ISupportInitialize iSupportInitialize = t as ISupportInitialize;
-			if (iSupportInitialize == null)
-			{
-				return t;
-			}
-			iSupportInitialize.EndInit();
-			return t;
-		}
-		
-		public static object FromStream(Type type, Stream stream)
-		{
-			object t = Serializer.NonGeneric.Deserialize(type, stream);
-			ISupportInitialize iSupportInitialize = t as ISupportInitialize;
-			if (iSupportInitialize == null)
-			{
-				return t;
-			}
-			iSupportInitialize.EndInit();
-			return t;
-		}
-	}
-}

+ 0 - 24
Unity/Assets/Scripts/Helper/ILHelper.cs

@@ -46,31 +46,7 @@ namespace ETModel
 				appDomain.RegisterCrossBindingAdaptor(adaptor);
 			}
 
-			// 初始化ILRuntime的protobuf
-			InitializeILRuntimeProtobuf(appDomain);
 			LitJson.JsonMapper.RegisterILRuntimeCLRRedirection(appDomain);
 		}
-
-		public static void InitializeILRuntimeProtobuf(ILRuntime.Runtime.Enviorment.AppDomain appDomain)
-		{
-			ProtoBuf.PType.RegisterFunctionCreateInstance((typeName)=>PType_CreateInstance(appDomain, typeName));
-			ProtoBuf.PType.RegisterFunctionGetRealType(PType_GetRealType);
-		}
-
-		private static object PType_CreateInstance(ILRuntime.Runtime.Enviorment.AppDomain appDomain, string typeName)
-		{
-			return appDomain.Instantiate(typeName);
-		}
-
-		private static Type PType_GetRealType(object o)
-		{
-			Type type = o.GetType();
-			if (type.FullName == "ILRuntime.Runtime.Intepreter.ILTypeInstance")
-			{
-				ILTypeInstance ilo = o as ILTypeInstance;
-				type = ProtoBuf.PType.FindType(ilo.Type.FullName);
-			}
-			return type;
-		}
 	}
 }

+ 2 - 0
Unity/Assets/Scripts/Init.cs

@@ -1,5 +1,7 @@
 using System;
+using System.IO;
 using System.Threading;
+using Google.Protobuf;
 using UnityEngine;
 
 namespace ETModel

+ 6 - 6
Unity/Assets/Scripts/Module/FrameSync/ClientFrameComponent.cs

@@ -44,17 +44,17 @@ namespace ETModel
             }
             SessionFrameMessage sessionFrameMessage = this.Queue.Dequeue();
             this.Frame = sessionFrameMessage.FrameMessage.Frame;
-
-            for (int i = 0; i < sessionFrameMessage.FrameMessage.Messages.Count; ++i)
+            for (int i = 0; i < sessionFrameMessage.FrameMessage.Message.Count; ++i)
             {
-	            OneFrameMessage oneFrameMessage = sessionFrameMessage.FrameMessage.Messages[i];
+	            OneFrameMessage oneFrameMessage = sessionFrameMessage.FrameMessage.Message[i];
 
 				Session session = sessionFrameMessage.Session;
 				OpcodeTypeComponent opcodeTypeComponent = session.Network.Entity.GetComponent<OpcodeTypeComponent>();
-	            Type type = opcodeTypeComponent.GetType(oneFrameMessage.Op);
+	            Type type = opcodeTypeComponent.GetType((ushort)oneFrameMessage.Op);
 
-	            IMessage message = (IMessage)session.Network.MessagePacker.DeserializeFrom(type, oneFrameMessage.AMessage);
-                Game.Scene.GetComponent<MessageDispatherComponent>().Handle(sessionFrameMessage.Session, new MessageInfo(oneFrameMessage.Op, message));
+	            byte[] bytes = oneFrameMessage.AMessage.ToByteArray();
+	            IMessage message = (IMessage)session.Network.MessagePacker.DeserializeFrom(type, bytes, 0, bytes.Length);
+                Game.Scene.GetComponent<MessageDispatherComponent>().Handle(sessionFrameMessage.Session, new MessageInfo((ushort)oneFrameMessage.Op, message));
             }
         }
     }

+ 22 - 25
Unity/Assets/Scripts/Module/FrameSync/FrameMessage.cs

@@ -1,42 +1,39 @@
 using System.Collections.Generic;
-using ProtoBuf;
 
 namespace ETModel
 {
 
     [Message(Opcode.OneFrameMessage)]
-    [ProtoContract]
     public partial class OneFrameMessage: IActorMessage
     {
-        [ProtoMember(90, IsRequired = true)]
-        public int RpcId { get; set; }
-
-        [ProtoMember(93, IsRequired = true)]
-        public long ActorId { get; set; }
-
-        [ProtoMember(1, IsRequired = true)]
-        public ushort Op;
-
-        [ProtoMember(2, IsRequired = true)]
-        public byte[] AMessage;
+        //[ProtoMember(90, IsRequired = true)]
+        //public int RpcId { get; set; }
+		//
+        //[ProtoMember(93, IsRequired = true)]
+        //public long ActorId { get; set; }
+		//
+        //[ProtoMember(1, IsRequired = true)]
+        //public ushort Op;
+		//
+        //[ProtoMember(2, IsRequired = true)]
+        //public byte[] AMessage;
 
     }
 
     [Message(Opcode.FrameMessage)]
-    [ProtoContract]
     public partial class FrameMessage: IActorMessage
     {
-        [ProtoMember(90, IsRequired = true)]
-        public int RpcId { get; set; }
-
-        [ProtoMember(93, IsRequired = true)]
-        public long ActorId { get; set; }
-
-        [ProtoMember(1, IsRequired = true)]
-        public int Frame;
-
-        [ProtoMember(2)]
-        public List<OneFrameMessage> Messages = new List<OneFrameMessage>();
+        //[ProtoMember(90, IsRequired = true)]
+        //public int RpcId { get; set; }
+		//
+        //[ProtoMember(93, IsRequired = true)]
+        //public long ActorId { get; set; }
+		//
+        //[ProtoMember(1, IsRequired = true)]
+        //public int Frame;
+		//
+        //[ProtoMember(2)]
+        //public List<OneFrameMessage> Messages = new List<OneFrameMessage>();
 
     }
 }

+ 213 - 0
Unity/Assets/Scripts/Module/FrameSync/FrameProto.cs

@@ -0,0 +1,213 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: FrameMessage.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using scg = global::System.Collections.Generic;
+namespace ETModel {
+
+  #region Messages
+  public partial class OneFrameMessage : pb::IMessage {
+    private static readonly pb::MessageParser<OneFrameMessage> _parser = new pb::MessageParser<OneFrameMessage>(() => new OneFrameMessage());
+    public static pb::MessageParser<OneFrameMessage> Parser { get { return _parser; } }
+
+    private int rpcId_;
+    public int RpcId {
+      get { return rpcId_; }
+      set {
+        rpcId_ = value;
+      }
+    }
+
+    private long actorId_;
+    public long ActorId {
+      get { return actorId_; }
+      set {
+        actorId_ = value;
+      }
+    }
+
+    private int op_;
+    public int Op {
+      get { return op_; }
+      set {
+        op_ = value;
+      }
+    }
+
+    private pb::ByteString aMessage_ = pb::ByteString.Empty;
+    public pb::ByteString AMessage {
+      get { return aMessage_; }
+      set {
+        aMessage_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Op != 0) {
+        output.WriteRawTag(8);
+        output.WriteInt32(Op);
+      }
+      if (AMessage.Length != 0) {
+        output.WriteRawTag(18);
+        output.WriteBytes(AMessage);
+      }
+      if (RpcId != 0) {
+        output.WriteRawTag(208, 5);
+        output.WriteInt32(RpcId);
+      }
+      if (ActorId != 0L) {
+        output.WriteRawTag(232, 5);
+        output.WriteInt64(ActorId);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (RpcId != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(RpcId);
+      }
+      if (ActorId != 0L) {
+        size += 2 + pb::CodedOutputStream.ComputeInt64Size(ActorId);
+      }
+      if (Op != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(Op);
+      }
+      if (AMessage.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeBytesSize(AMessage);
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            Op = input.ReadInt32();
+            break;
+          }
+          case 18: {
+            AMessage = input.ReadBytes();
+            break;
+          }
+          case 720: {
+            RpcId = input.ReadInt32();
+            break;
+          }
+          case 744: {
+            ActorId = input.ReadInt64();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  public partial class FrameMessage : pb::IMessage {
+    private static readonly pb::MessageParser<FrameMessage> _parser = new pb::MessageParser<FrameMessage>(() => new FrameMessage());
+    public static pb::MessageParser<FrameMessage> Parser { get { return _parser; } }
+
+    private int rpcId_;
+    public int RpcId {
+      get { return rpcId_; }
+      set {
+        rpcId_ = value;
+      }
+    }
+
+    private long actorId_;
+    public long ActorId {
+      get { return actorId_; }
+      set {
+        actorId_ = value;
+      }
+    }
+
+    private int frame_;
+    public int Frame {
+      get { return frame_; }
+      set {
+        frame_ = value;
+      }
+    }
+
+    private static readonly pb::FieldCodec<global::ETModel.OneFrameMessage> _repeated_message_codec
+        = pb::FieldCodec.ForMessage(18, global::ETModel.OneFrameMessage.Parser);
+    private pbc::RepeatedField<global::ETModel.OneFrameMessage> message_ = new pbc::RepeatedField<global::ETModel.OneFrameMessage>();
+    public pbc::RepeatedField<global::ETModel.OneFrameMessage> Message {
+      get { return message_; }
+      set { message_ = value; }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Frame != 0) {
+        output.WriteRawTag(8);
+        output.WriteInt32(Frame);
+      }
+      message_.WriteTo(output, _repeated_message_codec);
+      if (RpcId != 0) {
+        output.WriteRawTag(208, 5);
+        output.WriteInt32(RpcId);
+      }
+      if (ActorId != 0L) {
+        output.WriteRawTag(232, 5);
+        output.WriteInt64(ActorId);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (RpcId != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(RpcId);
+      }
+      if (ActorId != 0L) {
+        size += 2 + pb::CodedOutputStream.ComputeInt64Size(ActorId);
+      }
+      if (Frame != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(Frame);
+      }
+      size += message_.CalculateSize(_repeated_message_codec);
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            Frame = input.ReadInt32();
+            break;
+          }
+          case 18: {
+            message_.AddEntriesFrom(input, _repeated_message_codec);
+            break;
+          }
+          case 720: {
+            RpcId = input.ReadInt32();
+            break;
+          }
+          case 744: {
+            ActorId = input.ReadInt64();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code

+ 2 - 3
Unity/Assets/ThirdParty/Protobuf/Editor/protobuf-net.Reflection/CSharpCodeGenerator.cs.meta → Unity/Assets/Scripts/Module/FrameSync/FrameProto.cs.meta

@@ -1,8 +1,7 @@
 fileFormatVersion: 2
-guid: 9dd6ca7bc326d2b40b4ef50492e16a8d
-timeCreated: 1517401477
-licenseType: Free
+guid: 7089cb7212206ca49822de2b818704d2
 MonoImporter:
+  externalObjects: {}
   serializedVersion: 2
   defaultReferences: []
   executionOrder: 0

+ 1 - 6
Unity/Assets/Scripts/Module/Message/IActorMessage.cs

@@ -1,6 +1,4 @@
-using ProtoBuf;
-
-// 不要在这个文件加[ProtoInclude]跟[BsonKnowType]标签,加到InnerMessage.cs或者OuterMessage.cs里面去
+// 不要在这个文件加[ProtoInclude]跟[BsonKnowType]标签,加到InnerMessage.cs或者OuterMessage.cs里面去
 namespace ETModel
 {
 	public interface IActorMessage: IRequest
@@ -8,17 +6,14 @@ namespace ETModel
 		long ActorId { get; set; }
 	}
 
-	[ProtoContract]
 	public interface IActorRequest : IActorMessage
 	{
 	}
 
-	[ProtoContract]
 	public interface IActorResponse : IResponse
 	{
 	}
 
-	[ProtoContract]
 	public interface IFrameMessage : IMessage
 	{
 		long Id { get; set; }

+ 1 - 3
Unity/Assets/Scripts/Module/Message/IMessage.cs

@@ -1,6 +1,4 @@
-using ProtoBuf;
-
-// 不要在这个文件加[ProtoInclude]跟[BsonKnowType]标签,加到InnerMessage.cs或者OuterMessage.cs里面去
+// 不要在这个文件加[ProtoInclude]跟[BsonKnowType]标签,加到InnerMessage.cs或者OuterMessage.cs里面去
 namespace ETModel
 {
 	public interface IMessage

+ 1 - 9
Unity/Assets/Scripts/Module/Message/IMessagePacker.cs

@@ -6,15 +6,7 @@ namespace ETModel
 	public interface IMessagePacker
 	{
 		byte[] SerializeToByteArray(object obj);
-		string SerializeToText(object obj);
-
-		object DeserializeFrom(Type type, byte[] bytes);
-		object DeserializeFrom(Type type, Stream stream);
 		object DeserializeFrom(Type type, byte[] bytes, int index, int count);
-		T DeserializeFrom<T>(byte[] bytes);
-		T DeserializeFrom<T>(byte[] bytes, int index, int count);
-
-		T DeserializeFrom<T>(string str);
-		object DeserializeFrom(Type type, string str);
+		object DeserializeFrom(Type type, MemoryStream stream);
 	}
 }

+ 1 - 1
Unity/Assets/Scripts/Module/Message/NetOuterComponent.cs

@@ -22,7 +22,7 @@
 	{
 		public void Awake()
 		{
-			this.Awake(NetworkProtocol.KCP);
+			this.Awake(NetworkProtocol.TCP);
 			this.MessagePacker = new ProtobufPacker();
 			this.MessageDispatcher = new ClientDispatcher();
 		}

+ 1018 - 218
Unity/Assets/Scripts/Module/Message/OuterMessage.cs

@@ -1,220 +1,1020 @@
-using ProtoBuf;
-using ETModel;
-using System.Collections.Generic;
-using MongoDB.Bson.Serialization.Attributes;
-namespace ETModel
-{
-	[Message(OuterOpcode.Actor_Test)]
-	[ProtoContract]
-	public partial class Actor_Test: IActorMessage
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-		[ProtoMember(93, IsRequired = true)]
-		public long ActorId { get; set; }
-
-		[ProtoMember(1, IsRequired = true)]
-		public string Info;
-
-	}
-
-	[Message(OuterOpcode.Actor_TestRequest)]
-	[ProtoContract]
-	public partial class Actor_TestRequest: IActorRequest
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-		[ProtoMember(93, IsRequired = true)]
-		public long ActorId { get; set; }
-
-		[ProtoMember(1, IsRequired = true)]
-		public string request;
-
-	}
-
-	[Message(OuterOpcode.Actor_TestResponse)]
-	[ProtoContract]
-	public partial class Actor_TestResponse: IActorResponse
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-		[ProtoMember(91, IsRequired = true)]
-		public int Error { get; set; }
-
-		[ProtoMember(92, IsRequired = true)]
-		public string Message { get; set; }
-
-		[ProtoMember(1, IsRequired = true)]
-		public string response;
-
-	}
-
-	[Message(OuterOpcode.Actor_TransferRequest)]
-	[ProtoContract]
-	public partial class Actor_TransferRequest: IActorRequest
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-		[ProtoMember(93, IsRequired = true)]
-		public long ActorId { get; set; }
-
-		[ProtoMember(1, IsRequired = true)]
-		public int MapIndex;
-
-	}
-
-	[Message(OuterOpcode.Actor_TransferResponse)]
-	[ProtoContract]
-	public partial class Actor_TransferResponse: IActorResponse
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-		[ProtoMember(91, IsRequired = true)]
-		public int Error { get; set; }
-
-		[ProtoMember(92, IsRequired = true)]
-		public string Message { get; set; }
-
-	}
-
-	[Message(OuterOpcode.C2G_EnterMap)]
-	[ProtoContract]
-	public partial class C2G_EnterMap: IRequest
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-	}
-
-	[Message(OuterOpcode.G2C_EnterMap)]
-	[ProtoContract]
-	public partial class G2C_EnterMap: IResponse
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-		[ProtoMember(91, IsRequired = true)]
-		public int Error { get; set; }
-
-		[ProtoMember(92, IsRequired = true)]
-		public string Message { get; set; }
-
-		[ProtoMember(1, IsRequired = true)]
-		public long UnitId;
-
-		[ProtoMember(2, IsRequired = true)]
-		public int Count;
-
-	}
-
-	[Message(OuterOpcode.UnitInfo)]
-	[ProtoContract]
-	public partial class UnitInfo
-	{
-		[ProtoMember(1, IsRequired = true)]
-		public long UnitId;
-
-		[ProtoMember(2, IsRequired = true)]
-		public int X;
-
-		[ProtoMember(3, IsRequired = true)]
-		public int Z;
-
-	}
-
-	[Message(OuterOpcode.Actor_CreateUnits)]
-	[ProtoContract]
-	public partial class Actor_CreateUnits: IActorMessage
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-		[ProtoMember(93, IsRequired = true)]
-		public long ActorId { get; set; }
-
-		[ProtoMember(1, TypeName = "ETModel.UnitInfo")]
-		public List<UnitInfo> Units = new List<UnitInfo>();
-
-	}
-
-	[Message(OuterOpcode.Frame_ClickMap)]
-	[ProtoContract]
-	public partial class Frame_ClickMap: IFrameMessage
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-		[ProtoMember(94, IsRequired = true)]
-		public long Id { get; set; }
-
-		[ProtoMember(1, IsRequired = true)]
-		public int X;
-
-		[ProtoMember(2, IsRequired = true)]
-		public int Z;
-
-	}
-
-	[Message(OuterOpcode.C2M_Reload)]
-	[ProtoContract]
-	public partial class C2M_Reload: IRequest
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-		[ProtoMember(1, IsRequired = true)]
-		public AppType AppType;
-
-	}
-
-	[Message(OuterOpcode.M2C_Reload)]
-	[ProtoContract]
-	public partial class M2C_Reload: IResponse
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-		[ProtoMember(91, IsRequired = true)]
-		public int Error { get; set; }
-
-		[ProtoMember(92, IsRequired = true)]
-		public string Message { get; set; }
-
-	}
-
-	[Message(OuterOpcode.C2R_Ping)]
-	[ProtoContract]
-	public partial class C2R_Ping: IRequest
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-	}
-
-	[Message(OuterOpcode.R2C_Ping)]
-	[ProtoContract]
-	public partial class R2C_Ping: IResponse
-	{
-		[ProtoMember(90, IsRequired = true)]
-		public int RpcId { get; set; }
-
-		[ProtoMember(91, IsRequired = true)]
-		public int Error { get; set; }
-
-		[ProtoMember(92, IsRequired = true)]
-		public string Message { get; set; }
-
-	}
-
-	[Message(OuterOpcode.G2C_Test)]
-	[ProtoContract]
-	public partial class G2C_Test: IMessage
-	{
-	}
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: OuterMessage.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using scg = global::System.Collections.Generic;
+namespace ETModel {
+
+  #region Messages
+  public partial class Actor_Test : pb::IMessage {
+    private static readonly pb::MessageParser<Actor_Test> _parser = new pb::MessageParser<Actor_Test>(() => new Actor_Test());
+    public static pb::MessageParser<Actor_Test> Parser { get { return _parser; } }
+
+    private int rpcId_;
+    public int RpcId {
+      get { return rpcId_; }
+      set {
+        rpcId_ = value;
+      }
+    }
+
+    private long actorId_;
+    public long ActorId {
+      get { return actorId_; }
+      set {
+        actorId_ = value;
+      }
+    }
+
+    private string info_ = "";
+    public string Info {
+      get { return info_; }
+      set {
+        info_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Info.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Info);
+      }
+      if (RpcId != 0) {
+        output.WriteRawTag(208, 5);
+        output.WriteInt32(RpcId);
+      }
+      if (ActorId != 0L) {
+        output.WriteRawTag(232, 5);
+        output.WriteInt64(ActorId);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (RpcId != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(RpcId);
+      }
+      if (ActorId != 0L) {
+        size += 2 + pb::CodedOutputStream.ComputeInt64Size(ActorId);
+      }
+      if (Info.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Info);
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Info = input.ReadString();
+            break;
+          }
+          case 720: {
+            RpcId = input.ReadInt32();
+            break;
+          }
+          case 744: {
+            ActorId = input.ReadInt64();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  public partial class Actor_TestRequest : pb::IMessage {
+    private static readonly pb::MessageParser<Actor_TestRequest> _parser = new pb::MessageParser<Actor_TestRequest>(() => new Actor_TestRequest());
+    public static pb::MessageParser<Actor_TestRequest> Parser { get { return _parser; } }
+
+    private int rpcId_;
+    public int RpcId {
+      get { return rpcId_; }
+      set {
+        rpcId_ = value;
+      }
+    }
+
+    private long actorId_;
+    public long ActorId {
+      get { return actorId_; }
+      set {
+        actorId_ = value;
+      }
+    }
+
+    private string request_ = "";
+    public string Request {
+      get { return request_; }
+      set {
+        request_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Request.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Request);
+      }
+      if (RpcId != 0) {
+        output.WriteRawTag(208, 5);
+        output.WriteInt32(RpcId);
+      }
+      if (ActorId != 0L) {
+        output.WriteRawTag(232, 5);
+        output.WriteInt64(ActorId);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (RpcId != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(RpcId);
+      }
+      if (ActorId != 0L) {
+        size += 2 + pb::CodedOutputStream.ComputeInt64Size(ActorId);
+      }
+      if (Request.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Request);
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Request = input.ReadString();
+            break;
+          }
+          case 720: {
+            RpcId = input.ReadInt32();
+            break;
+          }
+          case 744: {
+            ActorId = input.ReadInt64();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  public partial class Actor_TestResponse : pb::IMessage {
+    private static readonly pb::MessageParser<Actor_TestResponse> _parser = new pb::MessageParser<Actor_TestResponse>(() => new Actor_TestResponse());
+    public static pb::MessageParser<Actor_TestResponse> Parser { get { return _parser; } }
+
+    private int rpcId_;
+    public int RpcId {
+      get { return rpcId_; }
+      set {
+        rpcId_ = value;
+      }
+    }
+
+    private int error_;
+    public int Error {
+      get { return error_; }
+      set {
+        error_ = value;
+      }
+    }
+
+    private string message_ = "";
+    public string Message {
+      get { return message_; }
+      set {
+        message_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private string response_ = "";
+    public string Response {
+      get { return response_; }
+      set {
+        response_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Response.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Response);
+      }
+      if (RpcId != 0) {
+        output.WriteRawTag(208, 5);
+        output.WriteInt32(RpcId);
+      }
+      if (Error != 0) {
+        output.WriteRawTag(216, 5);
+        output.WriteInt32(Error);
+      }
+      if (Message.Length != 0) {
+        output.WriteRawTag(226, 5);
+        output.WriteString(Message);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (RpcId != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(RpcId);
+      }
+      if (Error != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(Error);
+      }
+      if (Message.Length != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeStringSize(Message);
+      }
+      if (Response.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Response);
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Response = input.ReadString();
+            break;
+          }
+          case 720: {
+            RpcId = input.ReadInt32();
+            break;
+          }
+          case 728: {
+            Error = input.ReadInt32();
+            break;
+          }
+          case 738: {
+            Message = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  public partial class Actor_TransferRequest : pb::IMessage {
+    private static readonly pb::MessageParser<Actor_TransferRequest> _parser = new pb::MessageParser<Actor_TransferRequest>(() => new Actor_TransferRequest());
+    public static pb::MessageParser<Actor_TransferRequest> Parser { get { return _parser; } }
+
+    private int rpcId_;
+    public int RpcId {
+      get { return rpcId_; }
+      set {
+        rpcId_ = value;
+      }
+    }
+
+    private long actorId_;
+    public long ActorId {
+      get { return actorId_; }
+      set {
+        actorId_ = value;
+      }
+    }
+
+    private int mapIndex_;
+    public int MapIndex {
+      get { return mapIndex_; }
+      set {
+        mapIndex_ = value;
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (MapIndex != 0) {
+        output.WriteRawTag(8);
+        output.WriteInt32(MapIndex);
+      }
+      if (RpcId != 0) {
+        output.WriteRawTag(208, 5);
+        output.WriteInt32(RpcId);
+      }
+      if (ActorId != 0L) {
+        output.WriteRawTag(232, 5);
+        output.WriteInt64(ActorId);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (RpcId != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(RpcId);
+      }
+      if (ActorId != 0L) {
+        size += 2 + pb::CodedOutputStream.ComputeInt64Size(ActorId);
+      }
+      if (MapIndex != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(MapIndex);
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            MapIndex = input.ReadInt32();
+            break;
+          }
+          case 720: {
+            RpcId = input.ReadInt32();
+            break;
+          }
+          case 744: {
+            ActorId = input.ReadInt64();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  public partial class Actor_TransferResponse : pb::IMessage {
+    private static readonly pb::MessageParser<Actor_TransferResponse> _parser = new pb::MessageParser<Actor_TransferResponse>(() => new Actor_TransferResponse());
+    public static pb::MessageParser<Actor_TransferResponse> Parser { get { return _parser; } }
+
+    private int rpcId_;
+    public int RpcId {
+      get { return rpcId_; }
+      set {
+        rpcId_ = value;
+      }
+    }
+
+    private int error_;
+    public int Error {
+      get { return error_; }
+      set {
+        error_ = value;
+      }
+    }
+
+    private string message_ = "";
+    public string Message {
+      get { return message_; }
+      set {
+        message_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (RpcId != 0) {
+        output.WriteRawTag(208, 5);
+        output.WriteInt32(RpcId);
+      }
+      if (Error != 0) {
+        output.WriteRawTag(216, 5);
+        output.WriteInt32(Error);
+      }
+      if (Message.Length != 0) {
+        output.WriteRawTag(226, 5);
+        output.WriteString(Message);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (RpcId != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(RpcId);
+      }
+      if (Error != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(Error);
+      }
+      if (Message.Length != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeStringSize(Message);
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 720: {
+            RpcId = input.ReadInt32();
+            break;
+          }
+          case 728: {
+            Error = input.ReadInt32();
+            break;
+          }
+          case 738: {
+            Message = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  public partial class C2G_EnterMap : pb::IMessage {
+    private static readonly pb::MessageParser<C2G_EnterMap> _parser = new pb::MessageParser<C2G_EnterMap>(() => new C2G_EnterMap());
+    public static pb::MessageParser<C2G_EnterMap> Parser { get { return _parser; } }
+
+    private int rpcId_;
+    public int RpcId {
+      get { return rpcId_; }
+      set {
+        rpcId_ = value;
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (RpcId != 0) {
+        output.WriteRawTag(208, 5);
+        output.WriteInt32(RpcId);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (RpcId != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(RpcId);
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 720: {
+            RpcId = input.ReadInt32();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  public partial class G2C_EnterMap : pb::IMessage {
+    private static readonly pb::MessageParser<G2C_EnterMap> _parser = new pb::MessageParser<G2C_EnterMap>(() => new G2C_EnterMap());
+    public static pb::MessageParser<G2C_EnterMap> Parser { get { return _parser; } }
+
+    private int rpcId_;
+    public int RpcId {
+      get { return rpcId_; }
+      set {
+        rpcId_ = value;
+      }
+    }
+
+    private int error_;
+    public int Error {
+      get { return error_; }
+      set {
+        error_ = value;
+      }
+    }
+
+    private string message_ = "";
+    public string Message {
+      get { return message_; }
+      set {
+        message_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private long unitId_;
+    public long UnitId {
+      get { return unitId_; }
+      set {
+        unitId_ = value;
+      }
+    }
+
+    private int count_;
+    public int Count {
+      get { return count_; }
+      set {
+        count_ = value;
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (UnitId != 0L) {
+        output.WriteRawTag(8);
+        output.WriteInt64(UnitId);
+      }
+      if (Count != 0) {
+        output.WriteRawTag(16);
+        output.WriteInt32(Count);
+      }
+      if (RpcId != 0) {
+        output.WriteRawTag(208, 5);
+        output.WriteInt32(RpcId);
+      }
+      if (Error != 0) {
+        output.WriteRawTag(216, 5);
+        output.WriteInt32(Error);
+      }
+      if (Message.Length != 0) {
+        output.WriteRawTag(226, 5);
+        output.WriteString(Message);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (RpcId != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(RpcId);
+      }
+      if (Error != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(Error);
+      }
+      if (Message.Length != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeStringSize(Message);
+      }
+      if (UnitId != 0L) {
+        size += 1 + pb::CodedOutputStream.ComputeInt64Size(UnitId);
+      }
+      if (Count != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(Count);
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            UnitId = input.ReadInt64();
+            break;
+          }
+          case 16: {
+            Count = input.ReadInt32();
+            break;
+          }
+          case 720: {
+            RpcId = input.ReadInt32();
+            break;
+          }
+          case 728: {
+            Error = input.ReadInt32();
+            break;
+          }
+          case 738: {
+            Message = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  public partial class UnitInfo : pb::IMessage {
+    private static readonly pb::MessageParser<UnitInfo> _parser = new pb::MessageParser<UnitInfo>(() => new UnitInfo());
+    public static pb::MessageParser<UnitInfo> Parser { get { return _parser; } }
+
+    private long unitId_;
+    public long UnitId {
+      get { return unitId_; }
+      set {
+        unitId_ = value;
+      }
+    }
+
+    private int x_;
+    public int X {
+      get { return x_; }
+      set {
+        x_ = value;
+      }
+    }
+
+    private int z_;
+    public int Z {
+      get { return z_; }
+      set {
+        z_ = value;
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (UnitId != 0L) {
+        output.WriteRawTag(8);
+        output.WriteInt64(UnitId);
+      }
+      if (X != 0) {
+        output.WriteRawTag(16);
+        output.WriteInt32(X);
+      }
+      if (Z != 0) {
+        output.WriteRawTag(24);
+        output.WriteInt32(Z);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (UnitId != 0L) {
+        size += 1 + pb::CodedOutputStream.ComputeInt64Size(UnitId);
+      }
+      if (X != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(X);
+      }
+      if (Z != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(Z);
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            UnitId = input.ReadInt64();
+            break;
+          }
+          case 16: {
+            X = input.ReadInt32();
+            break;
+          }
+          case 24: {
+            Z = input.ReadInt32();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  public partial class Actor_CreateUnits : pb::IMessage {
+    private static readonly pb::MessageParser<Actor_CreateUnits> _parser = new pb::MessageParser<Actor_CreateUnits>(() => new Actor_CreateUnits());
+    public static pb::MessageParser<Actor_CreateUnits> Parser { get { return _parser; } }
+
+    private int rpcId_;
+    public int RpcId {
+      get { return rpcId_; }
+      set {
+        rpcId_ = value;
+      }
+    }
+
+    private long actorId_;
+    public long ActorId {
+      get { return actorId_; }
+      set {
+        actorId_ = value;
+      }
+    }
+
+    private static readonly pb::FieldCodec<global::ETModel.UnitInfo> _repeated_units_codec
+        = pb::FieldCodec.ForMessage(10, global::ETModel.UnitInfo.Parser);
+    private pbc::RepeatedField<global::ETModel.UnitInfo> units_ = new pbc::RepeatedField<global::ETModel.UnitInfo>();
+    public pbc::RepeatedField<global::ETModel.UnitInfo> Units {
+      get { return units_; }
+      set { units_ = value; }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      units_.WriteTo(output, _repeated_units_codec);
+      if (RpcId != 0) {
+        output.WriteRawTag(208, 5);
+        output.WriteInt32(RpcId);
+      }
+      if (ActorId != 0L) {
+        output.WriteRawTag(232, 5);
+        output.WriteInt64(ActorId);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (RpcId != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(RpcId);
+      }
+      if (ActorId != 0L) {
+        size += 2 + pb::CodedOutputStream.ComputeInt64Size(ActorId);
+      }
+      size += units_.CalculateSize(_repeated_units_codec);
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            units_.AddEntriesFrom(input, _repeated_units_codec);
+            break;
+          }
+          case 720: {
+            RpcId = input.ReadInt32();
+            break;
+          }
+          case 744: {
+            ActorId = input.ReadInt64();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  public partial class Frame_ClickMap : pb::IMessage {
+    private static readonly pb::MessageParser<Frame_ClickMap> _parser = new pb::MessageParser<Frame_ClickMap>(() => new Frame_ClickMap());
+    public static pb::MessageParser<Frame_ClickMap> Parser { get { return _parser; } }
+
+    private int rpcId_;
+    public int RpcId {
+      get { return rpcId_; }
+      set {
+        rpcId_ = value;
+      }
+    }
+
+    private long id_;
+    public long Id {
+      get { return id_; }
+      set {
+        id_ = value;
+      }
+    }
+
+    private int x_;
+    public int X {
+      get { return x_; }
+      set {
+        x_ = value;
+      }
+    }
+
+    private int z_;
+    public int Z {
+      get { return z_; }
+      set {
+        z_ = value;
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (X != 0) {
+        output.WriteRawTag(8);
+        output.WriteInt32(X);
+      }
+      if (Z != 0) {
+        output.WriteRawTag(16);
+        output.WriteInt32(Z);
+      }
+      if (RpcId != 0) {
+        output.WriteRawTag(208, 5);
+        output.WriteInt32(RpcId);
+      }
+      if (Id != 0L) {
+        output.WriteRawTag(240, 5);
+        output.WriteInt64(Id);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (RpcId != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(RpcId);
+      }
+      if (Id != 0L) {
+        size += 2 + pb::CodedOutputStream.ComputeInt64Size(Id);
+      }
+      if (X != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(X);
+      }
+      if (Z != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(Z);
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            X = input.ReadInt32();
+            break;
+          }
+          case 16: {
+            Z = input.ReadInt32();
+            break;
+          }
+          case 720: {
+            RpcId = input.ReadInt32();
+            break;
+          }
+          case 752: {
+            Id = input.ReadInt64();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  public partial class C2R_Ping : pb::IMessage {
+    private static readonly pb::MessageParser<C2R_Ping> _parser = new pb::MessageParser<C2R_Ping>(() => new C2R_Ping());
+    public static pb::MessageParser<C2R_Ping> Parser { get { return _parser; } }
+
+    private int rpcId_;
+    public int RpcId {
+      get { return rpcId_; }
+      set {
+        rpcId_ = value;
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (RpcId != 0) {
+        output.WriteRawTag(208, 5);
+        output.WriteInt32(RpcId);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (RpcId != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(RpcId);
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 720: {
+            RpcId = input.ReadInt32();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  public partial class R2C_Ping : pb::IMessage {
+    private static readonly pb::MessageParser<R2C_Ping> _parser = new pb::MessageParser<R2C_Ping>(() => new R2C_Ping());
+    public static pb::MessageParser<R2C_Ping> Parser { get { return _parser; } }
+
+    private int rpcId_;
+    public int RpcId {
+      get { return rpcId_; }
+      set {
+        rpcId_ = value;
+      }
+    }
+
+    private int error_;
+    public int Error {
+      get { return error_; }
+      set {
+        error_ = value;
+      }
+    }
+
+    private string message_ = "";
+    public string Message {
+      get { return message_; }
+      set {
+        message_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (RpcId != 0) {
+        output.WriteRawTag(208, 5);
+        output.WriteInt32(RpcId);
+      }
+      if (Error != 0) {
+        output.WriteRawTag(216, 5);
+        output.WriteInt32(Error);
+      }
+      if (Message.Length != 0) {
+        output.WriteRawTag(226, 5);
+        output.WriteString(Message);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (RpcId != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(RpcId);
+      }
+      if (Error != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(Error);
+      }
+      if (Message.Length != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeStringSize(Message);
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 720: {
+            RpcId = input.ReadInt32();
+            break;
+          }
+          case 728: {
+            Error = input.ReadInt32();
+            break;
+          }
+          case 738: {
+            Message = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  public partial class G2C_Test : pb::IMessage {
+    private static readonly pb::MessageParser<G2C_Test> _parser = new pb::MessageParser<G2C_Test>(() => new G2C_Test());
+    public static pb::MessageParser<G2C_Test> Parser { get { return _parser; } }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+        }
+      }
+    }
+
+  }
+
+  #endregion
 
 }
+
+#endregion Designer generated code

+ 46 - 5
Unity/Assets/Scripts/Module/Message/OuterOpcode.cs

@@ -1,3 +1,46 @@
+using ETModel;
+namespace ETModel
+{
+	[Message(OuterOpcode.Actor_Test)]
+	public partial class Actor_Test : IActorMessage {}
+
+	[Message(OuterOpcode.Actor_TestRequest)]
+	public partial class Actor_TestRequest : IActorRequest {}
+
+	[Message(OuterOpcode.Actor_TestResponse)]
+	public partial class Actor_TestResponse : IActorResponse {}
+
+	[Message(OuterOpcode.Actor_TransferRequest)]
+	public partial class Actor_TransferRequest : IActorRequest {}
+
+	[Message(OuterOpcode.Actor_TransferResponse)]
+	public partial class Actor_TransferResponse : IActorResponse {}
+
+	[Message(OuterOpcode.C2G_EnterMap)]
+	public partial class C2G_EnterMap : IRequest {}
+
+	[Message(OuterOpcode.G2C_EnterMap)]
+	public partial class G2C_EnterMap : IResponse {}
+
+	[Message(OuterOpcode.UnitInfo)]
+	public partial class UnitInfo {}
+
+	[Message(OuterOpcode.Actor_CreateUnits)]
+	public partial class Actor_CreateUnits : IActorMessage {}
+
+	[Message(OuterOpcode.Frame_ClickMap)]
+	public partial class Frame_ClickMap : IFrameMessage {}
+
+	[Message(OuterOpcode.C2R_Ping)]
+	public partial class C2R_Ping : IRequest {}
+
+	[Message(OuterOpcode.R2C_Ping)]
+	public partial class R2C_Ping : IResponse {}
+
+	[Message(OuterOpcode.G2C_Test)]
+	public partial class G2C_Test : IMessage {}
+
+}
 namespace ETModel
 {
 	public static partial class OuterOpcode
@@ -12,10 +55,8 @@ namespace ETModel
 		 public const ushort UnitInfo = 108;
 		 public const ushort Actor_CreateUnits = 109;
 		 public const ushort Frame_ClickMap = 110;
-		 public const ushort C2M_Reload = 111;
-		 public const ushort M2C_Reload = 112;
-		 public const ushort C2R_Ping = 113;
-		 public const ushort R2C_Ping = 114;
-		 public const ushort G2C_Test = 115;
+		 public const ushort C2R_Ping = 111;
+		 public const ushort R2C_Ping = 112;
+		 public const ushort G2C_Test = 113;
 	}
 }

+ 43 - 0
Unity/Assets/Scripts/Module/Message/ProtobufHelper.cs

@@ -0,0 +1,43 @@
+using System;
+using System.ComponentModel;
+using System.IO;
+using Google.Protobuf;
+
+namespace ETModel
+{
+	public static class ProtobufHelper
+	{
+		public static byte[] ToBytes(object message)
+		{
+			return ((Google.Protobuf.IMessage) message).ToByteArray();
+		}
+		
+		public static object FromBytes(Type type, byte[] bytes, int index, int count)
+		{
+			// 这个message可以从池中获取,减少gc
+			object message = Activator.CreateInstance(type);
+			((Google.Protobuf.IMessage)message).MergeFrom(bytes, index, count);
+			ISupportInitialize iSupportInitialize = message as ISupportInitialize;
+			if (iSupportInitialize == null)
+			{
+				return message;
+			}
+			iSupportInitialize.EndInit();
+			return message;
+		}
+		
+		public static object FromStream(Type type, MemoryStream stream)
+		{
+			// 这个message可以从池中获取,减少gc
+			object message = Activator.CreateInstance(type);
+			((Google.Protobuf.IMessage)message).MergeFrom(stream.GetBuffer(), (int)stream.Position, (int)stream.Length);
+			ISupportInitialize iSupportInitialize = message as ISupportInitialize;
+			if (iSupportInitialize == null)
+			{
+				return message;
+			}
+			iSupportInitialize.EndInit();
+			return message;
+		}
+	}
+}

+ 0 - 0
Unity/Assets/Scripts/Base/Helper/ProtobufHelper.cs.meta → Unity/Assets/Scripts/Module/Message/ProtobufHelper.cs.meta


+ 2 - 32
Unity/Assets/Scripts/Module/Message/ProtobufPacker.cs

@@ -10,44 +10,14 @@ namespace ETModel
 			return ProtobufHelper.ToBytes(obj);
 		}
 
-		public string SerializeToText(object obj)
-		{
-			return JsonHelper.ToJson(obj);
-		}
-
-		public object DeserializeFrom(Type type, byte[] bytes)
-		{
-			return ProtobufHelper.FromBytes(type, bytes);
-		}
-
-		public object DeserializeFrom(Type type, Stream stream)
-		{
-			return ProtobufHelper.FromStream(type, stream);
-		}
-
 		public object DeserializeFrom(Type type, byte[] bytes, int index, int count)
 		{
 			return ProtobufHelper.FromBytes(type, bytes, index, count);
 		}
 
-		public T DeserializeFrom<T>(byte[] bytes)
+		public object DeserializeFrom(Type type, MemoryStream stream)
 		{
-			return ProtobufHelper.FromBytes<T>(bytes);
-		}
-
-		public T DeserializeFrom<T>(byte[] bytes, int index, int count)
-		{
-			return ProtobufHelper.FromBytes<T>(bytes, index, count);
-		}
-
-		public T DeserializeFrom<T>(string str)
-		{
-			return JsonHelper.FromJson<T>(str);
-		}
-
-		public object DeserializeFrom(Type type, string str)
-		{
-			return JsonHelper.FromJson(type, str);
+			return ProtobufHelper.FromStream(type, stream);
 		}
 	}
 }

+ 0 - 1
Unity/Assets/Scripts/Module/Message/Session.cs

@@ -233,7 +233,6 @@ namespace ETModel
 			OpcodeTypeComponent opcodeTypeComponent = this.Network.Entity.GetComponent<OpcodeTypeComponent>();
 			ushort opcode = opcodeTypeComponent.GetOpcode(message.GetType());
 			byte[] bytes = this.Network.MessagePacker.SerializeToByteArray(message);
-
 			Send(flag, opcode, bytes);
 		}
 

+ 2 - 3
Unity/Assets/ThirdParty/Protobuf.meta → Unity/Assets/ThirdParty/Google.Protobuf.meta

@@ -1,9 +1,8 @@
 fileFormatVersion: 2
-guid: 44b468f70e36c914a906f4875c457513
+guid: 0c65cefeb5a4691489086c452ed06a7d
 folderAsset: yes
-timeCreated: 1517401476
-licenseType: Free
 DefaultImporter:
+  externalObjects: {}
   userData: 
   assetBundleName: 
   assetBundleVariant: 

+ 74 - 0
Unity/Assets/ThirdParty/Google.Protobuf/AdaptHelper.cs

@@ -0,0 +1,74 @@
+
+using System;
+using ILRuntime.CLR.Method;
+using ILRuntime.CLR.TypeSystem;
+using ILRuntime.Runtime.Enviorment;
+using ILRuntime.Runtime.Intepreter;
+using AppDomain = ILRuntime.Runtime.Enviorment.AppDomain;
+
+public static class AdaptHelper
+{
+    public class AdaptMethod
+    {
+        public string Name;
+        public int ParamCount;
+        public IMethod Method;
+    }
+
+
+    public static IMethod GetMethod(this ILType type, AdaptMethod m)
+    {
+        if (m.Method != null)
+            return m.Method;
+
+        m.Method = type.GetMethod(m.Name, m.ParamCount);
+        if (m.Method == null)
+        {
+            string baseClass = "";
+            if (type.FirstCLRBaseType != null)
+            {
+                baseClass = type.FirstCLRBaseType.FullName;
+            }
+            else if (type.FirstCLRInterface != null)
+            {
+                baseClass = type.FirstCLRInterface.FullName;
+            }
+
+            throw new Exception(string.Format("can't find the method: {0}.{1}:{2}, paramCount={3}", type.FullName, m.Name, baseClass, m.ParamCount));
+        }
+
+        return m.Method;
+    }
+}
+
+public abstract class MyAdaptor : CrossBindingAdaptorType
+{
+    protected AppDomain AppDomain { get; set; }
+    protected ILTypeInstance _instance;
+    private AdaptHelper.AdaptMethod[] _methods;
+
+    protected abstract AdaptHelper.AdaptMethod[] GetAdaptMethods();
+
+    public ILTypeInstance ILInstance
+    {
+        get { return _instance; }
+        set { _instance = value; }
+    }
+
+    protected object Invoke(int index, params object[] p)
+    {
+        if (_methods == null)
+            _methods = GetAdaptMethods();
+
+        var m = _instance.Type.GetMethod(_methods[index]);
+        return AppDomain.Invoke(m, _instance, p);
+    }
+
+    protected MyAdaptor(AppDomain appdomain, ILTypeInstance instance)
+    {
+        AppDomain = appdomain;
+        _instance = instance;
+    }
+
+}
+

+ 2 - 3
Unity/Assets/ThirdParty/Protobuf/Editor/protobuf-net.Reflection/CodeGenerator.OneOfStub.cs.meta → Unity/Assets/ThirdParty/Google.Protobuf/AdaptHelper.cs.meta

@@ -1,8 +1,7 @@
 fileFormatVersion: 2
-guid: eadc7291e5760b049b3413444376b292
-timeCreated: 1517401477
-licenseType: Free
+guid: 4640c013447589b43af10bf9115f6a1e
 MonoImporter:
+  externalObjects: {}
   serializedVersion: 2
   defaultReferences: []
   executionOrder: 0

+ 57 - 0
Unity/Assets/ThirdParty/Google.Protobuf/Adapt_IMessage.cs

@@ -0,0 +1,57 @@
+using System;
+using Google.Protobuf;
+using ILRuntime.Runtime.Enviorment;
+using ILRuntime.Runtime.Intepreter;
+using AppDomain = ILRuntime.Runtime.Enviorment.AppDomain;
+
+
+public class Adapt_IMessage : CrossBindingAdaptor
+{
+    public override Type BaseCLRType
+    {
+        get { return typeof(IMessage); }
+    }
+
+    public override Type AdaptorType
+    {
+        get { return typeof(Adaptor); }
+    }
+
+    public override object CreateCLRInstance(AppDomain appdomain, ILTypeInstance instance)
+    {
+        return new Adaptor(appdomain, instance);
+    }
+
+    public class Adaptor : MyAdaptor, IMessage
+    {
+        public Adaptor(AppDomain appdomain, ILTypeInstance instance) : base(appdomain,instance)
+        {
+        }
+
+        protected override AdaptHelper.AdaptMethod[] GetAdaptMethods()
+        {
+            AdaptHelper.AdaptMethod[] methods = 
+            {
+                new AdaptHelper.AdaptMethod {Name = "MergeFrom", ParamCount = 1}, 
+                new AdaptHelper.AdaptMethod {Name = "WriteTo", ParamCount = 1}, 
+                new AdaptHelper.AdaptMethod {Name = "CalculateSize", ParamCount = 0}, 
+            };
+            return methods;
+        }
+
+        public void MergeFrom(CodedInputStream input)
+        {
+            Invoke(0, input);
+        }
+
+        public void WriteTo(CodedOutputStream output)
+        {
+            Invoke(1, output);
+        }
+
+        public int CalculateSize()
+        {
+            return (int)Invoke(2);
+        }
+    }
+}

+ 2 - 3
Unity/Assets/ThirdParty/Protobuf/Editor/Protogen.cs.meta → Unity/Assets/ThirdParty/Google.Protobuf/Adapt_IMessage.cs.meta

@@ -1,8 +1,7 @@
 fileFormatVersion: 2
-guid: de9067302637f414bb5afb37d586a4e2
-timeCreated: 1517401477
-licenseType: Free
+guid: 6341dd86d1514904a8a295feeb5a2d87
 MonoImporter:
+  externalObjects: {}
   serializedVersion: 2
   defaultReferences: []
   executionOrder: 0

+ 79 - 0
Unity/Assets/ThirdParty/Google.Protobuf/ByteArray.cs

@@ -0,0 +1,79 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Provides a utility routine to copy small arrays much more quickly than Buffer.BlockCopy
+    /// </summary>
+    internal static class ByteArray
+    {
+        /// <summary>
+        /// The threshold above which you should use Buffer.BlockCopy rather than ByteArray.Copy
+        /// </summary>
+        private const int CopyThreshold = 12;
+
+        /// <summary>
+        /// Determines which copy routine to use based on the number of bytes to be copied.
+        /// </summary>
+        internal static void Copy(byte[] src, int srcOffset, byte[] dst, int dstOffset, int count)
+        {
+            if (count > CopyThreshold)
+            {
+                Buffer.BlockCopy(src, srcOffset, dst, dstOffset, count);
+            }
+            else
+            {
+                int stop = srcOffset + count;
+                for (int i = srcOffset; i < stop; i++)
+                {
+                    dst[dstOffset++] = src[i];
+                }
+            }
+        }
+
+        /// <summary>
+        /// Reverses the order of bytes in the array
+        /// </summary>
+        internal static void Reverse(byte[] bytes)
+        {
+            for (int first = 0, last = bytes.Length - 1; first < last; first++, last--)
+            {
+                byte temp = bytes[first];
+                bytes[first] = bytes[last];
+                bytes[last] = temp;
+            }
+        }
+    }
+}

+ 2 - 3
Unity/Assets/ThirdParty/Protobuf/Editor/protobuf-net.Reflection/CodeGenerator.cs.meta → Unity/Assets/ThirdParty/Google.Protobuf/ByteArray.cs.meta

@@ -1,8 +1,7 @@
 fileFormatVersion: 2
-guid: c84b4838bf8353749b0aef2f3445a446
-timeCreated: 1517401477
-licenseType: Free
+guid: cc6f6a4c966390c4da2d54d15368bd0d
 MonoImporter:
+  externalObjects: {}
   serializedVersion: 2
   defaultReferences: []
   executionOrder: 0

+ 378 - 0
Unity/Assets/ThirdParty/Google.Protobuf/ByteString.cs

@@ -0,0 +1,378 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using Google.Protobuf.Compatibility;
+using MongoDB.Bson.Serialization.Attributes;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Immutable array of bytes.
+    /// </summary>
+    public sealed class ByteString : IEnumerable<byte>, IEquatable<ByteString>
+    {
+        private static readonly ByteString empty = new ByteString(new byte[0]);
+
+        public byte[] bytes;
+
+        /// <summary>
+        /// Unsafe operations that can cause IO Failure and/or other catestrophic side-effects.
+        /// </summary>
+        internal static class Unsafe
+        {
+            /// <summary>
+            /// Constructs a new ByteString from the given byte array. The array is
+            /// *not* copied, and must not be modified after this constructor is called.
+            /// </summary>
+            internal static ByteString FromBytes(byte[] bytes)
+            {
+                return new ByteString(bytes);
+            }
+
+            /// <summary>
+            /// Provides direct, unrestricted access to the bytes contained in this instance.
+            /// You must not modify or resize the byte array returned by this method.
+            /// </summary>
+            internal static byte[] GetBuffer(ByteString bytes)
+            {
+                return bytes.bytes;
+            }
+        }
+
+        /// <summary>
+        /// Internal use only.  Ensure that the provided array is not mutated and belongs to this instance.
+        /// </summary>
+        internal static ByteString AttachBytes(byte[] bytes)
+        {
+            return new ByteString(bytes);
+        }
+        
+        public ByteString()
+        {}
+
+        public ByteString(List<byte> list)
+        {
+            this.bytes = list.ToArray();
+        }
+        /// <summary>
+        /// Constructs a new ByteString from the given byte array. The array is
+        /// *not* copied, and must not be modified after this constructor is called.
+        /// </summary>
+        public ByteString(byte[] bytes)
+        {
+            this.bytes = bytes;
+        }
+
+        /// <summary>
+        /// Returns an empty ByteString.
+        /// </summary>
+        public static ByteString Empty
+        {
+            get { return empty; }
+        }
+
+        /// <summary>
+        /// Returns the length of this ByteString in bytes.
+        /// </summary>
+        [BsonIgnore]
+        public int Length
+        {
+            get { return bytes.Length; }
+        }
+
+        /// <summary>
+        /// Returns <c>true</c> if this byte string is empty, <c>false</c> otherwise.
+        /// </summary>
+        [BsonIgnore]
+        public bool IsEmpty
+        {
+            get { return Length == 0; }
+        }
+
+        /// <summary>
+        /// Converts this <see cref="ByteString"/> into a byte array.
+        /// </summary>
+        /// <remarks>The data is copied - changes to the returned array will not be reflected in this <c>ByteString</c>.</remarks>
+        /// <returns>A byte array with the same data as this <c>ByteString</c>.</returns>
+        public byte[] ToByteArray()
+        {
+            return (byte[]) bytes.Clone();
+        }
+
+        /// <summary>
+        /// Converts this <see cref="ByteString"/> into a standard base64 representation.
+        /// </summary>
+        /// <returns>A base64 representation of this <c>ByteString</c>.</returns>
+        public string ToBase64()
+        {
+            return Convert.ToBase64String(bytes);
+        }
+
+        /// <summary>
+        /// Constructs a <see cref="ByteString" /> from the Base64 Encoded String.
+        /// </summary>
+        public static ByteString FromBase64(string bytes)
+        {
+            // By handling the empty string explicitly, we not only optimize but we fix a
+            // problem on CF 2.0. See issue 61 for details.
+            return bytes == "" ? Empty : new ByteString(Convert.FromBase64String(bytes));
+        }
+
+        /// <summary>
+        /// Constructs a <see cref="ByteString"/> from data in the given stream, synchronously.
+        /// </summary>
+        /// <remarks>If successful, <paramref name="stream"/> will be read completely, from the position
+        /// at the start of the call.</remarks>
+        /// <param name="stream">The stream to copy into a ByteString.</param>
+        /// <returns>A ByteString with content read from the given stream.</returns>
+        public static ByteString FromStream(Stream stream)
+        {
+            ProtoPreconditions.CheckNotNull(stream, "stream");
+            int capacity = stream.CanSeek ? checked((int) (stream.Length - stream.Position)) : 0;
+            var memoryStream = new MemoryStream(capacity);
+            stream.CopyTo(memoryStream);
+
+            // Avoid an extra copy if we can.
+            byte[] bytes = memoryStream.Length == memoryStream.Capacity ? memoryStream.GetBuffer() : memoryStream.ToArray();
+
+            return AttachBytes(bytes);
+        }
+
+        /// <summary>
+        /// Constructs a <see cref="ByteString" /> from the given array. The contents
+        /// are copied, so further modifications to the array will not
+        /// be reflected in the returned ByteString.
+        /// This method can also be invoked in <c>ByteString.CopyFrom(0xaa, 0xbb, ...)</c> form
+        /// which is primarily useful for testing.
+        /// </summary>
+        public static ByteString CopyFrom(params byte[] bytes)
+        {
+            return new ByteString((byte[]) bytes.Clone());
+        }
+
+        /// <summary>
+        /// Constructs a <see cref="ByteString" /> from a portion of a byte array.
+        /// </summary>
+        public static ByteString CopyFrom(byte[] bytes, int offset, int count)
+        {
+            byte[] portion = new byte[count];
+            ByteArray.Copy(bytes, offset, portion, 0, count);
+            return new ByteString(portion);
+        }
+
+        /// <summary>
+        /// Creates a new <see cref="ByteString" /> by encoding the specified text with
+        /// the given encoding.
+        /// </summary>
+        public static ByteString CopyFrom(string text, Encoding encoding)
+        {
+            return new ByteString(encoding.GetBytes(text));
+        }
+
+        /// <summary>
+        /// Creates a new <see cref="ByteString" /> by encoding the specified text in UTF-8.
+        /// </summary>
+        public static ByteString CopyFromUtf8(string text)
+        {
+            return CopyFrom(text, Encoding.UTF8);
+        }
+
+        /// <summary>
+        /// Retuns the byte at the given index.
+        /// </summary>
+        [BsonIgnore]
+        public byte this[int index]
+        {
+            get { return bytes[index]; }
+        }
+
+        /// <summary>
+        /// Converts this <see cref="ByteString"/> into a string by applying the given encoding.
+        /// </summary>
+        /// <remarks>
+        /// This method should only be used to convert binary data which was the result of encoding
+        /// text with the given encoding.
+        /// </remarks>
+        /// <param name="encoding">The encoding to use to decode the binary data into text.</param>
+        /// <returns>The result of decoding the binary data with the given decoding.</returns>
+        public string ToString(Encoding encoding)
+        {
+            return encoding.GetString(bytes, 0, bytes.Length);
+        }
+
+        /// <summary>
+        /// Converts this <see cref="ByteString"/> into a string by applying the UTF-8 encoding.
+        /// </summary>
+        /// <remarks>
+        /// This method should only be used to convert binary data which was the result of encoding
+        /// text with UTF-8.
+        /// </remarks>
+        /// <returns>The result of decoding the binary data with the given decoding.</returns>
+        public string ToStringUtf8()
+        {
+            return ToString(Encoding.UTF8);
+        }
+
+        /// <summary>
+        /// Returns an iterator over the bytes in this <see cref="ByteString"/>.
+        /// </summary>
+        /// <returns>An iterator over the bytes in this object.</returns>
+        public IEnumerator<byte> GetEnumerator()
+        {
+            return ((IEnumerable<byte>) bytes).GetEnumerator();
+        }
+
+        /// <summary>
+        /// Returns an iterator over the bytes in this <see cref="ByteString"/>.
+        /// </summary>
+        /// <returns>An iterator over the bytes in this object.</returns>
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return GetEnumerator();
+        }
+
+        /// <summary>
+        /// Creates a CodedInputStream from this ByteString's data.
+        /// </summary>
+        public CodedInputStream CreateCodedInput()
+        {
+            // We trust CodedInputStream not to reveal the provided byte array or modify it
+            return new CodedInputStream(bytes);
+        }
+
+        /// <summary>
+        /// Compares two byte strings for equality.
+        /// </summary>
+        /// <param name="lhs">The first byte string to compare.</param>
+        /// <param name="rhs">The second byte string to compare.</param>
+        /// <returns><c>true</c> if the byte strings are equal; false otherwise.</returns>
+        public static bool operator ==(ByteString lhs, ByteString rhs)
+        {
+            if (ReferenceEquals(lhs, rhs))
+            {
+                return true;
+            }
+            if (ReferenceEquals(lhs, null) || ReferenceEquals(rhs, null))
+            {
+                return false;
+            }
+            if (lhs.bytes.Length != rhs.bytes.Length)
+            {
+                return false;
+            }
+            for (int i = 0; i < lhs.Length; i++)
+            {
+                if (rhs.bytes[i] != lhs.bytes[i])
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        /// <summary>
+        /// Compares two byte strings for inequality.
+        /// </summary>
+        /// <param name="lhs">The first byte string to compare.</param>
+        /// <param name="rhs">The second byte string to compare.</param>
+        /// <returns><c>false</c> if the byte strings are equal; true otherwise.</returns>
+        public static bool operator !=(ByteString lhs, ByteString rhs)
+        {
+            return !(lhs == rhs);
+        }
+
+        /// <summary>
+        /// Compares this byte string with another object.
+        /// </summary>
+        /// <param name="obj">The object to compare this with.</param>
+        /// <returns><c>true</c> if <paramref name="obj"/> refers to an equal <see cref="ByteString"/>; <c>false</c> otherwise.</returns>
+        public override bool Equals(object obj)
+        {
+            return this == (obj as ByteString);
+        }
+
+        /// <summary>
+        /// Returns a hash code for this object. Two equal byte strings
+        /// will return the same hash code.
+        /// </summary>
+        /// <returns>A hash code for this object.</returns>
+        public override int GetHashCode()
+        {
+            int ret = 23;
+            foreach (byte b in bytes)
+            {
+                ret = (ret * 31) + b;
+            }
+            return ret;
+        }
+
+        /// <summary>
+        /// Compares this byte string with another.
+        /// </summary>
+        /// <param name="other">The <see cref="ByteString"/> to compare this with.</param>
+        /// <returns><c>true</c> if <paramref name="other"/> refers to an equal byte string; <c>false</c> otherwise.</returns>
+        public bool Equals(ByteString other)
+        {
+            return this == other;
+        }
+
+        /// <summary>
+        /// Used internally by CodedOutputStream to avoid creating a copy for the write
+        /// </summary>
+        internal void WriteRawBytesTo(CodedOutputStream outputStream)
+        {
+            outputStream.WriteRawBytes(bytes, 0, bytes.Length);
+        }
+
+        /// <summary>
+        /// Copies the entire byte array to the destination array provided at the offset specified.
+        /// </summary>
+        public void CopyTo(byte[] array, int position)
+        {
+            ByteArray.Copy(bytes, 0, array, position, bytes.Length);
+        }
+
+        /// <summary>
+        /// Writes the entire byte array to the provided stream
+        /// </summary>
+        public void WriteTo(Stream outputStream)
+        {
+            outputStream.Write(bytes, 0, bytes.Length);
+        }
+    }
+}

+ 11 - 0
Unity/Assets/ThirdParty/Google.Protobuf/ByteString.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 0495e4b3ba1ec7f498d877a234323a35
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 1274 - 0
Unity/Assets/ThirdParty/Google.Protobuf/CodedInputStream.cs

@@ -0,0 +1,1274 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using Google.Protobuf.Collections;
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Reads and decodes protocol message fields.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// This class is generally used by generated code to read appropriate
+    /// primitives from the stream. It effectively encapsulates the lowest
+    /// levels of protocol buffer format.
+    /// </para>
+    /// <para>
+    /// Repeated fields and map fields are not handled by this class; use <see cref="RepeatedField{T}"/>
+    /// and <see cref="MapField{TKey, TValue}"/> to serialize such fields.
+    /// </para>
+    /// </remarks>
+    public sealed class CodedInputStream : IDisposable
+    {
+        /// <summary>
+        /// Whether to leave the underlying stream open when disposing of this stream.
+        /// This is always true when there's no stream.
+        /// </summary>
+        private readonly bool leaveOpen;
+
+        /// <summary>
+        /// Buffer of data read from the stream or provided at construction time.
+        /// </summary>
+        private readonly byte[] buffer;
+
+        /// <summary>
+        /// The index of the buffer at which we need to refill from the stream (if there is one).
+        /// </summary>
+        private int bufferSize;
+
+        private int bufferSizeAfterLimit = 0;
+        /// <summary>
+        /// The position within the current buffer (i.e. the next byte to read)
+        /// </summary>
+        private int bufferPos = 0;
+
+        /// <summary>
+        /// The stream to read further input from, or null if the byte array buffer was provided
+        /// directly on construction, with no further data available.
+        /// </summary>
+        private readonly Stream input;
+
+        /// <summary>
+        /// The last tag we read. 0 indicates we've read to the end of the stream
+        /// (or haven't read anything yet).
+        /// </summary>
+        private uint lastTag = 0;
+
+        /// <summary>
+        /// The next tag, used to store the value read by PeekTag.
+        /// </summary>
+        private uint nextTag = 0;
+        private bool hasNextTag = false;
+
+        internal const int DefaultRecursionLimit = 64;
+        internal const int DefaultSizeLimit = 64 << 20; // 64MB
+        internal const int BufferSize = 4096;
+
+        /// <summary>
+        /// The total number of bytes read before the current buffer. The
+        /// total bytes read up to the current position can be computed as
+        /// totalBytesRetired + bufferPos.
+        /// </summary>
+        private int totalBytesRetired = 0;
+
+        /// <summary>
+        /// The absolute position of the end of the current message.
+        /// </summary> 
+        private int currentLimit = int.MaxValue;
+
+        private int recursionDepth = 0;
+
+        private readonly int recursionLimit;
+        private readonly int sizeLimit;
+
+        #region Construction
+        // Note that the checks are performed such that we don't end up checking obviously-valid things
+        // like non-null references for arrays we've just created.
+
+        /// <summary>
+        /// Creates a new CodedInputStream reading data from the given byte array.
+        /// </summary>
+        public CodedInputStream(byte[] buffer) : this(null, ProtoPreconditions.CheckNotNull(buffer, "buffer"), 0, buffer.Length, true)
+        {            
+        }
+
+        /// <summary>
+        /// Creates a new <see cref="CodedInputStream"/> that reads from the given byte array slice.
+        /// </summary>
+        public CodedInputStream(byte[] buffer, int offset, int length)
+            : this(null, ProtoPreconditions.CheckNotNull(buffer, "buffer"), offset, offset + length, true)
+        {            
+            if (offset < 0 || offset > buffer.Length)
+            {
+                throw new ArgumentOutOfRangeException("offset", "Offset must be within the buffer");
+            }
+            if (length < 0 || offset + length > buffer.Length)
+            {
+                throw new ArgumentOutOfRangeException("length", "Length must be non-negative and within the buffer");
+            }
+        }
+
+        /// <summary>
+        /// Creates a new <see cref="CodedInputStream"/> reading data from the given stream, which will be disposed
+        /// when the returned object is disposed.
+        /// </summary>
+        /// <param name="input">The stream to read from.</param>
+        public CodedInputStream(Stream input) : this(input, false)
+        {
+        }
+
+        /// <summary>
+        /// Creates a new <see cref="CodedInputStream"/> reading data from the given stream.
+        /// </summary>
+        /// <param name="input">The stream to read from.</param>
+        /// <param name="leaveOpen"><c>true</c> to leave <paramref name="input"/> open when the returned
+        /// <c cref="CodedInputStream"/> is disposed; <c>false</c> to dispose of the given stream when the
+        /// returned object is disposed.</param>
+        public CodedInputStream(Stream input, bool leaveOpen)
+            : this(ProtoPreconditions.CheckNotNull(input, "input"), new byte[BufferSize], 0, 0, leaveOpen)
+        {
+        }
+        
+        /// <summary>
+        /// Creates a new CodedInputStream reading data from the given
+        /// stream and buffer, using the default limits.
+        /// </summary>
+        internal CodedInputStream(Stream input, byte[] buffer, int bufferPos, int bufferSize, bool leaveOpen)
+        {
+            this.input = input;
+            this.buffer = buffer;
+            this.bufferPos = bufferPos;
+            this.bufferSize = bufferSize;
+            this.sizeLimit = DefaultSizeLimit;
+            this.recursionLimit = DefaultRecursionLimit;
+            this.leaveOpen = leaveOpen;
+        }
+
+        /// <summary>
+        /// Creates a new CodedInputStream reading data from the given
+        /// stream and buffer, using the specified limits.
+        /// </summary>
+        /// <remarks>
+        /// This chains to the version with the default limits instead of vice versa to avoid
+        /// having to check that the default values are valid every time.
+        /// </remarks>
+        internal CodedInputStream(Stream input, byte[] buffer, int bufferPos, int bufferSize, int sizeLimit, int recursionLimit, bool leaveOpen)
+            : this(input, buffer, bufferPos, bufferSize, leaveOpen)
+        {
+            if (sizeLimit <= 0)
+            {
+                throw new ArgumentOutOfRangeException("sizeLimit", "Size limit must be positive");
+            }
+            if (recursionLimit <= 0)
+            {
+                throw new ArgumentOutOfRangeException("recursionLimit!", "Recursion limit must be positive");
+            }
+            this.sizeLimit = sizeLimit;
+            this.recursionLimit = recursionLimit;
+        }
+        #endregion
+
+        /// <summary>
+        /// Creates a <see cref="CodedInputStream"/> with the specified size and recursion limits, reading
+        /// from an input stream.
+        /// </summary>
+        /// <remarks>
+        /// This method exists separately from the constructor to reduce the number of constructor overloads.
+        /// It is likely to be used considerably less frequently than the constructors, as the default limits
+        /// are suitable for most use cases.
+        /// </remarks>
+        /// <param name="input">The input stream to read from</param>
+        /// <param name="sizeLimit">The total limit of data to read from the stream.</param>
+        /// <param name="recursionLimit">The maximum recursion depth to allow while reading.</param>
+        /// <returns>A <c>CodedInputStream</c> reading from <paramref name="input"/> with the specified size
+        /// and recursion limits.</returns>
+        public static CodedInputStream CreateWithLimits(Stream input, int sizeLimit, int recursionLimit)
+        {
+            // Note: we may want an overload accepting leaveOpen
+            return new CodedInputStream(input, new byte[BufferSize], 0, 0, sizeLimit, recursionLimit, false);
+        }
+
+        /// <summary>
+        /// Returns the current position in the input stream, or the position in the input buffer
+        /// </summary>
+        public long Position 
+        {
+            get
+            {
+                if (input != null)
+                {
+                    return input.Position - ((bufferSize + bufferSizeAfterLimit) - bufferPos);
+                }
+                return bufferPos;
+            }
+        }
+
+        /// <summary>
+        /// Returns the last tag read, or 0 if no tags have been read or we've read beyond
+        /// the end of the stream.
+        /// </summary>
+        internal uint LastTag { get { return lastTag; } }
+
+        /// <summary>
+        /// Returns the size limit for this stream.
+        /// </summary>
+        /// <remarks>
+        /// This limit is applied when reading from the underlying stream, as a sanity check. It is
+        /// not applied when reading from a byte array data source without an underlying stream.
+        /// The default value is 64MB.
+        /// </remarks>
+        /// <value>
+        /// The size limit.
+        /// </value>
+        public int SizeLimit { get { return sizeLimit; } }
+
+        /// <summary>
+        /// Returns the recursion limit for this stream. This limit is applied whilst reading messages,
+        /// to avoid maliciously-recursive data.
+        /// </summary>
+        /// <remarks>
+        /// The default limit is 64.
+        /// </remarks>
+        /// <value>
+        /// The recursion limit for this stream.
+        /// </value>
+        public int RecursionLimit { get { return recursionLimit; } }
+
+        /// <summary>
+        /// Disposes of this instance, potentially closing any underlying stream.
+        /// </summary>
+        /// <remarks>
+        /// As there is no flushing to perform here, disposing of a <see cref="CodedInputStream"/> which
+        /// was constructed with the <c>leaveOpen</c> option parameter set to <c>true</c> (or one which
+        /// was constructed to read from a byte array) has no effect.
+        /// </remarks>
+        public void Dispose()
+        {
+            if (!leaveOpen)
+            {
+                input.Dispose();
+            }
+        }
+
+        #region Validation
+        /// <summary>
+        /// Verifies that the last call to ReadTag() returned tag 0 - in other words,
+        /// we've reached the end of the stream when we expected to.
+        /// </summary>
+        /// <exception cref="InvalidProtocolBufferException">The 
+        /// tag read was not the one specified</exception>
+        internal void CheckReadEndOfStreamTag()
+        {
+            if (lastTag != 0)
+            {
+                throw InvalidProtocolBufferException.MoreDataAvailable();
+            }
+        }
+        #endregion
+
+        #region Reading of tags etc
+
+        /// <summary>
+        /// Peeks at the next field tag. This is like calling <see cref="ReadTag"/>, but the
+        /// tag is not consumed. (So a subsequent call to <see cref="ReadTag"/> will return the
+        /// same value.)
+        /// </summary>
+        public uint PeekTag()
+        {
+            if (hasNextTag)
+            {
+                return nextTag;
+            }
+
+            uint savedLast = lastTag;
+            nextTag = ReadTag();
+            hasNextTag = true;
+            lastTag = savedLast; // Undo the side effect of ReadTag
+            return nextTag;
+        }
+
+        /// <summary>
+        /// Reads a field tag, returning the tag of 0 for "end of stream".
+        /// </summary>
+        /// <remarks>
+        /// If this method returns 0, it doesn't necessarily mean the end of all
+        /// the data in this CodedInputStream; it may be the end of the logical stream
+        /// for an embedded message, for example.
+        /// </remarks>
+        /// <returns>The next field tag, or 0 for end of stream. (0 is never a valid tag.)</returns>
+        public uint ReadTag()
+        {
+            if (hasNextTag)
+            {
+                lastTag = nextTag;
+                hasNextTag = false;
+                return lastTag;
+            }
+
+            // Optimize for the incredibly common case of having at least two bytes left in the buffer,
+            // and those two bytes being enough to get the tag. This will be true for fields up to 4095.
+            if (bufferPos + 2 <= bufferSize)
+            {
+                int tmp = buffer[bufferPos++];
+                if (tmp < 128)
+                {
+                    lastTag = (uint)tmp;
+                }
+                else
+                {
+                    int result = tmp & 0x7f;
+                    if ((tmp = buffer[bufferPos++]) < 128)
+                    {
+                        result |= tmp << 7;
+                        lastTag = (uint) result;
+                    }
+                    else
+                    {
+                        // Nope, rewind and go the potentially slow route.
+                        bufferPos -= 2;
+                        lastTag = ReadRawVarint32();
+                    }
+                }
+            }
+            else
+            {
+                if (IsAtEnd)
+                {
+                    lastTag = 0;
+                    return 0; // This is the only case in which we return 0.
+                }
+
+                lastTag = ReadRawVarint32();
+            }
+            if (lastTag == 0)
+            {
+                // If we actually read zero, that's not a valid tag.
+                throw InvalidProtocolBufferException.InvalidTag();
+            }
+            return lastTag;
+        }
+
+        /// <summary>
+        /// Skips the data for the field with the tag we've just read.
+        /// This should be called directly after <see cref="ReadTag"/>, when
+        /// the caller wishes to skip an unknown field.
+        /// </summary>
+        /// <remarks>
+        /// This method throws <see cref="InvalidProtocolBufferException"/> if the last-read tag was an end-group tag.
+        /// If a caller wishes to skip a group, they should skip the whole group, by calling this method after reading the
+        /// start-group tag. This behavior allows callers to call this method on any field they don't understand, correctly
+        /// resulting in an error if an end-group tag has not been paired with an earlier start-group tag.
+        /// </remarks>
+        /// <exception cref="InvalidProtocolBufferException">The last tag was an end-group tag</exception>
+        /// <exception cref="InvalidOperationException">The last read operation read to the end of the logical stream</exception>
+        public void SkipLastField()
+        {
+            if (lastTag == 0)
+            {
+                throw new InvalidOperationException("SkipLastField cannot be called at the end of a stream");
+            }
+            switch (WireFormat.GetTagWireType(lastTag))
+            {
+                case WireFormat.WireType.StartGroup:
+                    SkipGroup(lastTag);
+                    break;
+                case WireFormat.WireType.EndGroup:
+                    throw new InvalidProtocolBufferException("SkipLastField called on an end-group tag, indicating that the corresponding start-group was missing");
+                case WireFormat.WireType.Fixed32:
+                    ReadFixed32();
+                    break;
+                case WireFormat.WireType.Fixed64:
+                    ReadFixed64();
+                    break;
+                case WireFormat.WireType.LengthDelimited:
+                    var length = ReadLength();
+                    SkipRawBytes(length);
+                    break;
+                case WireFormat.WireType.Varint:
+                    ReadRawVarint32();
+                    break;
+            }
+        }
+
+        private void SkipGroup(uint startGroupTag)
+        {
+            // Note: Currently we expect this to be the way that groups are read. We could put the recursion
+            // depth changes into the ReadTag method instead, potentially...
+            recursionDepth++;
+            if (recursionDepth >= recursionLimit)
+            {
+                throw InvalidProtocolBufferException.RecursionLimitExceeded();
+            }
+            uint tag;
+            while (true)
+            {
+                tag = ReadTag();
+                if (tag == 0)
+                {
+                    throw InvalidProtocolBufferException.TruncatedMessage();
+                }
+                // Can't call SkipLastField for this case- that would throw.
+                if (WireFormat.GetTagWireType(tag) == WireFormat.WireType.EndGroup)
+                {
+                    break;
+                }
+                // This recursion will allow us to handle nested groups.
+                SkipLastField();
+            }
+            int startField = WireFormat.GetTagFieldNumber(startGroupTag);
+            int endField = WireFormat.GetTagFieldNumber(tag);
+            if (startField != endField)
+            {
+                throw new InvalidProtocolBufferException("Mismatched end-group tag. Started with field " + startField + "; ended with field " + endField);
+            }
+            recursionDepth--;
+        }
+
+        /// <summary>
+        /// Reads a double field from the stream.
+        /// </summary>
+        public double ReadDouble()
+        {
+            return BitConverter.Int64BitsToDouble((long) ReadRawLittleEndian64());
+        }
+
+        /// <summary>
+        /// Reads a float field from the stream.
+        /// </summary>
+        public float ReadFloat()
+        {
+            if (BitConverter.IsLittleEndian && 4 <= bufferSize - bufferPos)
+            {
+                float ret = BitConverter.ToSingle(buffer, bufferPos);
+                bufferPos += 4;
+                return ret;
+            }
+            else
+            {
+                byte[] rawBytes = ReadRawBytes(4);
+                if (!BitConverter.IsLittleEndian)
+                {
+                    ByteArray.Reverse(rawBytes);
+                }
+                return BitConverter.ToSingle(rawBytes, 0);
+            }
+        }
+
+        /// <summary>
+        /// Reads a uint64 field from the stream.
+        /// </summary>
+        public ulong ReadUInt64()
+        {
+            return ReadRawVarint64();
+        }
+
+        /// <summary>
+        /// Reads an int64 field from the stream.
+        /// </summary>
+        public long ReadInt64()
+        {
+            return (long) ReadRawVarint64();
+        }
+
+        /// <summary>
+        /// Reads an int32 field from the stream.
+        /// </summary>
+        public int ReadInt32()
+        {
+            return (int) ReadRawVarint32();
+        }
+
+        /// <summary>
+        /// Reads a fixed64 field from the stream.
+        /// </summary>
+        public ulong ReadFixed64()
+        {
+            return ReadRawLittleEndian64();
+        }
+
+        /// <summary>
+        /// Reads a fixed32 field from the stream.
+        /// </summary>
+        public uint ReadFixed32()
+        {
+            return ReadRawLittleEndian32();
+        }
+
+        /// <summary>
+        /// Reads a bool field from the stream.
+        /// </summary>
+        public bool ReadBool()
+        {
+            return ReadRawVarint32() != 0;
+        }
+
+        /// <summary>
+        /// Reads a string field from the stream.
+        /// </summary>
+        public string ReadString()
+        {
+            int length = ReadLength();
+            // No need to read any data for an empty string.
+            if (length == 0)
+            {
+                return "";
+            }
+            if (length <= bufferSize - bufferPos)
+            {
+                // Fast path:  We already have the bytes in a contiguous buffer, so
+                //   just copy directly from it.
+                String result = CodedOutputStream.Utf8Encoding.GetString(buffer, bufferPos, length);
+                bufferPos += length;
+                return result;
+            }
+            // Slow path: Build a byte array first then copy it.
+            return CodedOutputStream.Utf8Encoding.GetString(ReadRawBytes(length), 0, length);
+        }
+
+        /// <summary>
+        /// Reads an embedded message field value from the stream.
+        /// </summary>   
+        public void ReadMessage(IMessage builder)
+        {
+            int length = ReadLength();
+            if (recursionDepth >= recursionLimit)
+            {
+                throw InvalidProtocolBufferException.RecursionLimitExceeded();
+            }
+            int oldLimit = PushLimit(length);
+            ++recursionDepth;
+            builder.MergeFrom(this);
+            CheckReadEndOfStreamTag();
+            // Check that we've read exactly as much data as expected.
+            if (!ReachedLimit)
+            {
+                throw InvalidProtocolBufferException.TruncatedMessage();
+            }
+            --recursionDepth;
+            PopLimit(oldLimit);
+        }
+
+        /// <summary>
+        /// Reads a bytes field value from the stream.
+        /// </summary>   
+        public ByteString ReadBytes()
+        {
+            int length = ReadLength();
+            if (length <= bufferSize - bufferPos && length > 0)
+            {
+                // Fast path:  We already have the bytes in a contiguous buffer, so
+                //   just copy directly from it.
+                ByteString result = ByteString.CopyFrom(buffer, bufferPos, length);
+                bufferPos += length;
+                return result;
+            }
+            else
+            {
+                // Slow path:  Build a byte array and attach it to a new ByteString.
+                return ByteString.AttachBytes(ReadRawBytes(length));
+            }
+        }
+
+        /// <summary>
+        /// Reads a uint32 field value from the stream.
+        /// </summary>   
+        public uint ReadUInt32()
+        {
+            return ReadRawVarint32();
+        }
+
+        /// <summary>
+        /// Reads an enum field value from the stream.
+        /// </summary>   
+        public int ReadEnum()
+        {
+            // Currently just a pass-through, but it's nice to separate it logically from WriteInt32.
+            return (int) ReadRawVarint32();
+        }
+
+        /// <summary>
+        /// Reads an sfixed32 field value from the stream.
+        /// </summary>   
+        public int ReadSFixed32()
+        {
+            return (int) ReadRawLittleEndian32();
+        }
+
+        /// <summary>
+        /// Reads an sfixed64 field value from the stream.
+        /// </summary>   
+        public long ReadSFixed64()
+        {
+            return (long) ReadRawLittleEndian64();
+        }
+
+        /// <summary>
+        /// Reads an sint32 field value from the stream.
+        /// </summary>   
+        public int ReadSInt32()
+        {
+            return DecodeZigZag32(ReadRawVarint32());
+        }
+
+        /// <summary>
+        /// Reads an sint64 field value from the stream.
+        /// </summary>   
+        public long ReadSInt64()
+        {
+            return DecodeZigZag64(ReadRawVarint64());
+        }
+
+        /// <summary>
+        /// Reads a length for length-delimited data.
+        /// </summary>
+        /// <remarks>
+        /// This is internally just reading a varint, but this method exists
+        /// to make the calling code clearer.
+        /// </remarks>
+        public int ReadLength()
+        {
+            return (int) ReadRawVarint32();
+        }
+
+        /// <summary>
+        /// Peeks at the next tag in the stream. If it matches <paramref name="tag"/>,
+        /// the tag is consumed and the method returns <c>true</c>; otherwise, the
+        /// stream is left in the original position and the method returns <c>false</c>.
+        /// </summary>
+        public bool MaybeConsumeTag(uint tag)
+        {
+            if (PeekTag() == tag)
+            {
+                hasNextTag = false;
+                return true;
+            }
+            return false;
+        }
+
+        #endregion
+
+        #region Underlying reading primitives
+
+        /// <summary>
+        /// Same code as ReadRawVarint32, but read each byte individually, checking for
+        /// buffer overflow.
+        /// </summary>
+        private uint SlowReadRawVarint32()
+        {
+            int tmp = ReadRawByte();
+            if (tmp < 128)
+            {
+                return (uint) tmp;
+            }
+            int result = tmp & 0x7f;
+            if ((tmp = ReadRawByte()) < 128)
+            {
+                result |= tmp << 7;
+            }
+            else
+            {
+                result |= (tmp & 0x7f) << 7;
+                if ((tmp = ReadRawByte()) < 128)
+                {
+                    result |= tmp << 14;
+                }
+                else
+                {
+                    result |= (tmp & 0x7f) << 14;
+                    if ((tmp = ReadRawByte()) < 128)
+                    {
+                        result |= tmp << 21;
+                    }
+                    else
+                    {
+                        result |= (tmp & 0x7f) << 21;
+                        result |= (tmp = ReadRawByte()) << 28;
+                        if (tmp >= 128)
+                        {
+                            // Discard upper 32 bits.
+                            for (int i = 0; i < 5; i++)
+                            {
+                                if (ReadRawByte() < 128)
+                                {
+                                    return (uint) result;
+                                }
+                            }
+                            throw InvalidProtocolBufferException.MalformedVarint();
+                        }
+                    }
+                }
+            }
+            return (uint) result;
+        }
+
+        /// <summary>
+        /// Reads a raw Varint from the stream.  If larger than 32 bits, discard the upper bits.
+        /// This method is optimised for the case where we've got lots of data in the buffer.
+        /// That means we can check the size just once, then just read directly from the buffer
+        /// without constant rechecking of the buffer length.
+        /// </summary>
+        internal uint ReadRawVarint32()
+        {
+            if (bufferPos + 5 > bufferSize)
+            {
+                return SlowReadRawVarint32();
+            }
+
+            int tmp = buffer[bufferPos++];
+            if (tmp < 128)
+            {
+                return (uint) tmp;
+            }
+            int result = tmp & 0x7f;
+            if ((tmp = buffer[bufferPos++]) < 128)
+            {
+                result |= tmp << 7;
+            }
+            else
+            {
+                result |= (tmp & 0x7f) << 7;
+                if ((tmp = buffer[bufferPos++]) < 128)
+                {
+                    result |= tmp << 14;
+                }
+                else
+                {
+                    result |= (tmp & 0x7f) << 14;
+                    if ((tmp = buffer[bufferPos++]) < 128)
+                    {
+                        result |= tmp << 21;
+                    }
+                    else
+                    {
+                        result |= (tmp & 0x7f) << 21;
+                        result |= (tmp = buffer[bufferPos++]) << 28;
+                        if (tmp >= 128)
+                        {
+                            // Discard upper 32 bits.
+                            // Note that this has to use ReadRawByte() as we only ensure we've
+                            // got at least 5 bytes at the start of the method. This lets us
+                            // use the fast path in more cases, and we rarely hit this section of code.
+                            for (int i = 0; i < 5; i++)
+                            {
+                                if (ReadRawByte() < 128)
+                                {
+                                    return (uint) result;
+                                }
+                            }
+                            throw InvalidProtocolBufferException.MalformedVarint();
+                        }
+                    }
+                }
+            }
+            return (uint) result;
+        }
+
+        /// <summary>
+        /// Reads a varint from the input one byte at a time, so that it does not
+        /// read any bytes after the end of the varint. If you simply wrapped the
+        /// stream in a CodedInputStream and used ReadRawVarint32(Stream)
+        /// then you would probably end up reading past the end of the varint since
+        /// CodedInputStream buffers its input.
+        /// </summary>
+        /// <param name="input"></param>
+        /// <returns></returns>
+        internal static uint ReadRawVarint32(Stream input)
+        {
+            int result = 0;
+            int offset = 0;
+            for (; offset < 32; offset += 7)
+            {
+                int b = input.ReadByte();
+                if (b == -1)
+                {
+                    throw InvalidProtocolBufferException.TruncatedMessage();
+                }
+                result |= (b & 0x7f) << offset;
+                if ((b & 0x80) == 0)
+                {
+                    return (uint) result;
+                }
+            }
+            // Keep reading up to 64 bits.
+            for (; offset < 64; offset += 7)
+            {
+                int b = input.ReadByte();
+                if (b == -1)
+                {
+                    throw InvalidProtocolBufferException.TruncatedMessage();
+                }
+                if ((b & 0x80) == 0)
+                {
+                    return (uint) result;
+                }
+            }
+            throw InvalidProtocolBufferException.MalformedVarint();
+        }
+
+        /// <summary>
+        /// Reads a raw varint from the stream.
+        /// </summary>
+        internal ulong ReadRawVarint64()
+        {
+            int shift = 0;
+            ulong result = 0;
+            while (shift < 64)
+            {
+                byte b = ReadRawByte();
+                result |= (ulong) (b & 0x7F) << shift;
+                if ((b & 0x80) == 0)
+                {
+                    return result;
+                }
+                shift += 7;
+            }
+            throw InvalidProtocolBufferException.MalformedVarint();
+        }
+
+        /// <summary>
+        /// Reads a 32-bit little-endian integer from the stream.
+        /// </summary>
+        internal uint ReadRawLittleEndian32()
+        {
+            uint b1 = ReadRawByte();
+            uint b2 = ReadRawByte();
+            uint b3 = ReadRawByte();
+            uint b4 = ReadRawByte();
+            return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24);
+        }
+
+        /// <summary>
+        /// Reads a 64-bit little-endian integer from the stream.
+        /// </summary>
+        internal ulong ReadRawLittleEndian64()
+        {
+            ulong b1 = ReadRawByte();
+            ulong b2 = ReadRawByte();
+            ulong b3 = ReadRawByte();
+            ulong b4 = ReadRawByte();
+            ulong b5 = ReadRawByte();
+            ulong b6 = ReadRawByte();
+            ulong b7 = ReadRawByte();
+            ulong b8 = ReadRawByte();
+            return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24)
+                   | (b5 << 32) | (b6 << 40) | (b7 << 48) | (b8 << 56);
+        }
+
+        /// <summary>
+        /// Decode a 32-bit value with ZigZag encoding.
+        /// </summary>
+        /// <remarks>
+        /// ZigZag encodes signed integers into values that can be efficiently
+        /// encoded with varint.  (Otherwise, negative values must be 
+        /// sign-extended to 64 bits to be varint encoded, thus always taking
+        /// 10 bytes on the wire.)
+        /// </remarks>
+        internal static int DecodeZigZag32(uint n)
+        {
+            return (int)(n >> 1) ^ -(int)(n & 1);
+        }
+
+        /// <summary>
+        /// Decode a 32-bit value with ZigZag encoding.
+        /// </summary>
+        /// <remarks>
+        /// ZigZag encodes signed integers into values that can be efficiently
+        /// encoded with varint.  (Otherwise, negative values must be 
+        /// sign-extended to 64 bits to be varint encoded, thus always taking
+        /// 10 bytes on the wire.)
+        /// </remarks>
+        internal static long DecodeZigZag64(ulong n)
+        {
+            return (long)(n >> 1) ^ -(long)(n & 1);
+        }
+        #endregion
+
+        #region Internal reading and buffer management
+
+        /// <summary>
+        /// Sets currentLimit to (current position) + byteLimit. This is called
+        /// when descending into a length-delimited embedded message. The previous
+        /// limit is returned.
+        /// </summary>
+        /// <returns>The old limit.</returns>
+        internal int PushLimit(int byteLimit)
+        {
+            if (byteLimit < 0)
+            {
+                throw InvalidProtocolBufferException.NegativeSize();
+            }
+            byteLimit += totalBytesRetired + bufferPos;
+            int oldLimit = currentLimit;
+            if (byteLimit > oldLimit)
+            {
+                throw InvalidProtocolBufferException.TruncatedMessage();
+            }
+            currentLimit = byteLimit;
+
+            RecomputeBufferSizeAfterLimit();
+
+            return oldLimit;
+        }
+
+        private void RecomputeBufferSizeAfterLimit()
+        {
+            bufferSize += bufferSizeAfterLimit;
+            int bufferEnd = totalBytesRetired + bufferSize;
+            if (bufferEnd > currentLimit)
+            {
+                // Limit is in current buffer.
+                bufferSizeAfterLimit = bufferEnd - currentLimit;
+                bufferSize -= bufferSizeAfterLimit;
+            }
+            else
+            {
+                bufferSizeAfterLimit = 0;
+            }
+        }
+
+        /// <summary>
+        /// Discards the current limit, returning the previous limit.
+        /// </summary>
+        internal void PopLimit(int oldLimit)
+        {
+            currentLimit = oldLimit;
+            RecomputeBufferSizeAfterLimit();
+        }
+
+        /// <summary>
+        /// Returns whether or not all the data before the limit has been read.
+        /// </summary>
+        /// <returns></returns>
+        internal bool ReachedLimit
+        {
+            get
+            {
+                if (currentLimit == int.MaxValue)
+                {
+                    return false;
+                }
+                int currentAbsolutePosition = totalBytesRetired + bufferPos;
+                return currentAbsolutePosition >= currentLimit;
+            }
+        }
+
+        /// <summary>
+        /// Returns true if the stream has reached the end of the input. This is the
+        /// case if either the end of the underlying input source has been reached or
+        /// the stream has reached a limit created using PushLimit.
+        /// </summary>
+        public bool IsAtEnd
+        {
+            get { return bufferPos == bufferSize && !RefillBuffer(false); }
+        }
+
+        /// <summary>
+        /// Called when buffer is empty to read more bytes from the
+        /// input.  If <paramref name="mustSucceed"/> is true, RefillBuffer() gurantees that
+        /// either there will be at least one byte in the buffer when it returns
+        /// or it will throw an exception.  If <paramref name="mustSucceed"/> is false,
+        /// RefillBuffer() returns false if no more bytes were available.
+        /// </summary>
+        /// <param name="mustSucceed"></param>
+        /// <returns></returns>
+        private bool RefillBuffer(bool mustSucceed)
+        {
+            if (bufferPos < bufferSize)
+            {
+                throw new InvalidOperationException("RefillBuffer() called when buffer wasn't empty.");
+            }
+
+            if (totalBytesRetired + bufferSize == currentLimit)
+            {
+                // Oops, we hit a limit.
+                if (mustSucceed)
+                {
+                    throw InvalidProtocolBufferException.TruncatedMessage();
+                }
+                else
+                {
+                    return false;
+                }
+            }
+
+            totalBytesRetired += bufferSize;
+
+            bufferPos = 0;
+            bufferSize = (input == null) ? 0 : input.Read(buffer, 0, buffer.Length);
+            if (bufferSize < 0)
+            {
+                throw new InvalidOperationException("Stream.Read returned a negative count");
+            }
+            if (bufferSize == 0)
+            {
+                if (mustSucceed)
+                {
+                    throw InvalidProtocolBufferException.TruncatedMessage();
+                }
+                else
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                RecomputeBufferSizeAfterLimit();
+                int totalBytesRead =
+                    totalBytesRetired + bufferSize + bufferSizeAfterLimit;
+                if (totalBytesRead > sizeLimit || totalBytesRead < 0)
+                {
+                    throw InvalidProtocolBufferException.SizeLimitExceeded();
+                }
+                return true;
+            }
+        }
+
+        /// <summary>
+        /// Read one byte from the input.
+        /// </summary>
+        /// <exception cref="InvalidProtocolBufferException">
+        /// the end of the stream or the current limit was reached
+        /// </exception>
+        internal byte ReadRawByte()
+        {
+            if (bufferPos == bufferSize)
+            {
+                RefillBuffer(true);
+            }
+            return buffer[bufferPos++];
+        }
+
+        /// <summary>
+        /// Reads a fixed size of bytes from the input.
+        /// </summary>
+        /// <exception cref="InvalidProtocolBufferException">
+        /// the end of the stream or the current limit was reached
+        /// </exception>
+        internal byte[] ReadRawBytes(int size)
+        {
+            if (size < 0)
+            {
+                throw InvalidProtocolBufferException.NegativeSize();
+            }
+
+            if (totalBytesRetired + bufferPos + size > currentLimit)
+            {
+                // Read to the end of the stream (up to the current limit) anyway.
+                SkipRawBytes(currentLimit - totalBytesRetired - bufferPos);
+                // Then fail.
+                throw InvalidProtocolBufferException.TruncatedMessage();
+            }
+
+            if (size <= bufferSize - bufferPos)
+            {
+                // We have all the bytes we need already.
+                byte[] bytes = new byte[size];
+                ByteArray.Copy(buffer, bufferPos, bytes, 0, size);
+                bufferPos += size;
+                return bytes;
+            }
+            else if (size < buffer.Length)
+            {
+                // Reading more bytes than are in the buffer, but not an excessive number
+                // of bytes.  We can safely allocate the resulting array ahead of time.
+
+                // First copy what we have.
+                byte[] bytes = new byte[size];
+                int pos = bufferSize - bufferPos;
+                ByteArray.Copy(buffer, bufferPos, bytes, 0, pos);
+                bufferPos = bufferSize;
+
+                // We want to use RefillBuffer() and then copy from the buffer into our
+                // byte array rather than reading directly into our byte array because
+                // the input may be unbuffered.
+                RefillBuffer(true);
+
+                while (size - pos > bufferSize)
+                {
+                    Buffer.BlockCopy(buffer, 0, bytes, pos, bufferSize);
+                    pos += bufferSize;
+                    bufferPos = bufferSize;
+                    RefillBuffer(true);
+                }
+
+                ByteArray.Copy(buffer, 0, bytes, pos, size - pos);
+                bufferPos = size - pos;
+
+                return bytes;
+            }
+            else
+            {
+                // The size is very large.  For security reasons, we can't allocate the
+                // entire byte array yet.  The size comes directly from the input, so a
+                // maliciously-crafted message could provide a bogus very large size in
+                // order to trick the app into allocating a lot of memory.  We avoid this
+                // by allocating and reading only a small chunk at a time, so that the
+                // malicious message must actually *be* extremely large to cause
+                // problems.  Meanwhile, we limit the allowed size of a message elsewhere.
+
+                // Remember the buffer markers since we'll have to copy the bytes out of
+                // it later.
+                int originalBufferPos = bufferPos;
+                int originalBufferSize = bufferSize;
+
+                // Mark the current buffer consumed.
+                totalBytesRetired += bufferSize;
+                bufferPos = 0;
+                bufferSize = 0;
+
+                // Read all the rest of the bytes we need.
+                int sizeLeft = size - (originalBufferSize - originalBufferPos);
+                List<byte[]> chunks = new List<byte[]>();
+
+                while (sizeLeft > 0)
+                {
+                    byte[] chunk = new byte[Math.Min(sizeLeft, buffer.Length)];
+                    int pos = 0;
+                    while (pos < chunk.Length)
+                    {
+                        int n = (input == null) ? -1 : input.Read(chunk, pos, chunk.Length - pos);
+                        if (n <= 0)
+                        {
+                            throw InvalidProtocolBufferException.TruncatedMessage();
+                        }
+                        totalBytesRetired += n;
+                        pos += n;
+                    }
+                    sizeLeft -= chunk.Length;
+                    chunks.Add(chunk);
+                }
+
+                // OK, got everything.  Now concatenate it all into one buffer.
+                byte[] bytes = new byte[size];
+
+                // Start by copying the leftover bytes from this.buffer.
+                int newPos = originalBufferSize - originalBufferPos;
+                ByteArray.Copy(buffer, originalBufferPos, bytes, 0, newPos);
+
+                // And now all the chunks.
+                foreach (byte[] chunk in chunks)
+                {
+                    Buffer.BlockCopy(chunk, 0, bytes, newPos, chunk.Length);
+                    newPos += chunk.Length;
+                }
+
+                // Done.
+                return bytes;
+            }
+        }
+
+        /// <summary>
+        /// Reads and discards <paramref name="size"/> bytes.
+        /// </summary>
+        /// <exception cref="InvalidProtocolBufferException">the end of the stream
+        /// or the current limit was reached</exception>
+        private void SkipRawBytes(int size)
+        {
+            if (size < 0)
+            {
+                throw InvalidProtocolBufferException.NegativeSize();
+            }
+
+            if (totalBytesRetired + bufferPos + size > currentLimit)
+            {
+                // Read to the end of the stream anyway.
+                SkipRawBytes(currentLimit - totalBytesRetired - bufferPos);
+                // Then fail.
+                throw InvalidProtocolBufferException.TruncatedMessage();
+            }
+
+            if (size <= bufferSize - bufferPos)
+            {
+                // We have all the bytes we need already.
+                bufferPos += size;
+            }
+            else
+            {
+                // Skipping more bytes than are in the buffer.  First skip what we have.
+                int pos = bufferSize - bufferPos;
+
+                // ROK 5/7/2013 Issue #54: should retire all bytes in buffer (bufferSize)
+                // totalBytesRetired += pos;
+                totalBytesRetired += bufferSize;
+                
+                bufferPos = 0;
+                bufferSize = 0;
+
+                // Then skip directly from the InputStream for the rest.
+                if (pos < size)
+                {
+                    if (input == null)
+                    {
+                        throw InvalidProtocolBufferException.TruncatedMessage();
+                    }
+                    SkipImpl(size - pos);
+                    totalBytesRetired += size - pos;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Abstraction of skipping to cope with streams which can't really skip.
+        /// </summary>
+        private void SkipImpl(int amountToSkip)
+        {
+            if (input.CanSeek)
+            {
+                long previousPosition = input.Position;
+                input.Position += amountToSkip;
+                if (input.Position != previousPosition + amountToSkip)
+                {
+                    throw InvalidProtocolBufferException.TruncatedMessage();
+                }
+            }
+            else
+            {
+                byte[] skipBuffer = new byte[Math.Min(1024, amountToSkip)];
+                while (amountToSkip > 0)
+                {
+                    int bytesRead = input.Read(skipBuffer, 0, Math.Min(skipBuffer.Length, amountToSkip));
+                    if (bytesRead <= 0)
+                    {
+                        throw InvalidProtocolBufferException.TruncatedMessage();
+                    }
+                    amountToSkip -= bytesRead;
+                }
+            }
+        }
+
+        #endregion
+    }
+}

+ 11 - 0
Unity/Assets/ThirdParty/Google.Protobuf/CodedInputStream.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 1df2eb703cafa984fa2b4ea1d596b0cd
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 304 - 0
Unity/Assets/ThirdParty/Google.Protobuf/CodedOutputStream.ComputeSize.cs

@@ -0,0 +1,304 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+
+namespace Google.Protobuf
+{
+    // This part of CodedOutputStream provides all the static entry points that are used
+    // by generated code and internally to compute the size of messages prior to being
+    // written to an instance of CodedOutputStream.
+    public sealed partial class CodedOutputStream
+    {
+        private const int LittleEndian64Size = 8;
+        private const int LittleEndian32Size = 4;        
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode a
+        /// double field, including the tag.
+        /// </summary>
+        public static int ComputeDoubleSize(double value)
+        {
+            return LittleEndian64Size;
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode a
+        /// float field, including the tag.
+        /// </summary>
+        public static int ComputeFloatSize(float value)
+        {
+            return LittleEndian32Size;
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode a
+        /// uint64 field, including the tag.
+        /// </summary>
+        public static int ComputeUInt64Size(ulong value)
+        {
+            return ComputeRawVarint64Size(value);
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode an
+        /// int64 field, including the tag.
+        /// </summary>
+        public static int ComputeInt64Size(long value)
+        {
+            return ComputeRawVarint64Size((ulong) value);
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode an
+        /// int32 field, including the tag.
+        /// </summary>
+        public static int ComputeInt32Size(int value)
+        {
+            if (value >= 0)
+            {
+                return ComputeRawVarint32Size((uint) value);
+            }
+            else
+            {
+                // Must sign-extend.
+                return 10;
+            }
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode a
+        /// fixed64 field, including the tag.
+        /// </summary>
+        public static int ComputeFixed64Size(ulong value)
+        {
+            return LittleEndian64Size;
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode a
+        /// fixed32 field, including the tag.
+        /// </summary>
+        public static int ComputeFixed32Size(uint value)
+        {
+            return LittleEndian32Size;
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode a
+        /// bool field, including the tag.
+        /// </summary>
+        public static int ComputeBoolSize(bool value)
+        {
+            return 1;
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode a
+        /// string field, including the tag.
+        /// </summary>
+        public static int ComputeStringSize(String value)
+        {
+            int byteArraySize = Utf8Encoding.GetByteCount(value);
+            return ComputeLengthSize(byteArraySize) + byteArraySize;
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode a
+        /// group field, including the tag.
+        /// </summary>
+        public static int ComputeGroupSize(IMessage value)
+        {
+            return value.CalculateSize();
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode an
+        /// embedded message field, including the tag.
+        /// </summary>
+        public static int ComputeMessageSize(IMessage value)
+        {
+            int size = value.CalculateSize();
+            return ComputeLengthSize(size) + size;
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode a
+        /// bytes field, including the tag.
+        /// </summary>
+        public static int ComputeBytesSize(ByteString value)
+        {
+            return ComputeLengthSize(value.Length) + value.Length;
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode a
+        /// uint32 field, including the tag.
+        /// </summary>
+        public static int ComputeUInt32Size(uint value)
+        {
+            return ComputeRawVarint32Size(value);
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode a
+        /// enum field, including the tag. The caller is responsible for
+        /// converting the enum value to its numeric value.
+        /// </summary>
+        public static int ComputeEnumSize(int value)
+        {
+            // Currently just a pass-through, but it's nice to separate it logically.
+            return ComputeInt32Size(value);
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode an
+        /// sfixed32 field, including the tag.
+        /// </summary>
+        public static int ComputeSFixed32Size(int value)
+        {
+            return LittleEndian32Size;
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode an
+        /// sfixed64 field, including the tag.
+        /// </summary>
+        public static int ComputeSFixed64Size(long value)
+        {
+            return LittleEndian64Size;
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode an
+        /// sint32 field, including the tag.
+        /// </summary>
+        public static int ComputeSInt32Size(int value)
+        {
+            return ComputeRawVarint32Size(EncodeZigZag32(value));
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode an
+        /// sint64 field, including the tag.
+        /// </summary>
+        public static int ComputeSInt64Size(long value)
+        {
+            return ComputeRawVarint64Size(EncodeZigZag64(value));
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode a length,
+        /// as written by <see cref="WriteLength"/>.
+        /// </summary>
+        public static int ComputeLengthSize(int length)
+        {
+            return ComputeRawVarint32Size((uint) length);
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode a varint.
+        /// </summary>
+        public static int ComputeRawVarint32Size(uint value)
+        {
+            if ((value & (0xffffffff << 7)) == 0)
+            {
+                return 1;
+            }
+            if ((value & (0xffffffff << 14)) == 0)
+            {
+                return 2;
+            }
+            if ((value & (0xffffffff << 21)) == 0)
+            {
+                return 3;
+            }
+            if ((value & (0xffffffff << 28)) == 0)
+            {
+                return 4;
+            }
+            return 5;
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode a varint.
+        /// </summary>
+        public static int ComputeRawVarint64Size(ulong value)
+        {
+            if ((value & (0xffffffffffffffffL << 7)) == 0)
+            {
+                return 1;
+            }
+            if ((value & (0xffffffffffffffffL << 14)) == 0)
+            {
+                return 2;
+            }
+            if ((value & (0xffffffffffffffffL << 21)) == 0)
+            {
+                return 3;
+            }
+            if ((value & (0xffffffffffffffffL << 28)) == 0)
+            {
+                return 4;
+            }
+            if ((value & (0xffffffffffffffffL << 35)) == 0)
+            {
+                return 5;
+            }
+            if ((value & (0xffffffffffffffffL << 42)) == 0)
+            {
+                return 6;
+            }
+            if ((value & (0xffffffffffffffffL << 49)) == 0)
+            {
+                return 7;
+            }
+            if ((value & (0xffffffffffffffffL << 56)) == 0)
+            {
+                return 8;
+            }
+            if ((value & (0xffffffffffffffffL << 63)) == 0)
+            {
+                return 9;
+            }
+            return 10;
+        }
+
+        /// <summary>
+        /// Computes the number of bytes that would be needed to encode a tag.
+        /// </summary>
+        public static int ComputeTagSize(int fieldNumber)
+        {
+            return ComputeRawVarint32Size(WireFormat.MakeTag(fieldNumber, 0));
+        }
+    }
+}

+ 11 - 0
Unity/Assets/ThirdParty/Google.Protobuf/CodedOutputStream.ComputeSize.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c94acc4c66cb8e14ca00789b21ef4dde
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 761 - 0
Unity/Assets/ThirdParty/Google.Protobuf/CodedOutputStream.cs

@@ -0,0 +1,761 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using Google.Protobuf.Collections;
+using System;
+using System.IO;
+using System.Text;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Encodes and writes protocol message fields.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// This class is generally used by generated code to write appropriate
+    /// primitives to the stream. It effectively encapsulates the lowest
+    /// levels of protocol buffer format. Unlike some other implementations,
+    /// this does not include combined "write tag and value" methods. Generated
+    /// code knows the exact byte representations of the tags they're going to write,
+    /// so there's no need to re-encode them each time. Manually-written code calling
+    /// this class should just call one of the <c>WriteTag</c> overloads before each value.
+    /// </para>
+    /// <para>
+    /// Repeated fields and map fields are not handled by this class; use <c>RepeatedField&lt;T&gt;</c>
+    /// and <c>MapField&lt;TKey, TValue&gt;</c> to serialize such fields.
+    /// </para>
+    /// </remarks>
+    public sealed partial class CodedOutputStream : IDisposable
+    {
+        // "Local" copy of Encoding.UTF8, for efficiency. (Yes, it makes a difference.)
+        internal static readonly Encoding Utf8Encoding = Encoding.UTF8;
+
+        /// <summary>
+        /// The buffer size used by CreateInstance(Stream).
+        /// </summary>
+        public static readonly int DefaultBufferSize = 4096;
+
+        private readonly bool leaveOpen;
+        private readonly byte[] buffer;
+        private readonly int limit;
+        private int position;
+        private readonly Stream output;
+
+        #region Construction
+        /// <summary>
+        /// Creates a new CodedOutputStream that writes directly to the given
+        /// byte array. If more bytes are written than fit in the array,
+        /// OutOfSpaceException will be thrown.
+        /// </summary>
+        public CodedOutputStream(byte[] flatArray) : this(flatArray, 0, flatArray.Length)
+        {
+        }
+
+        /// <summary>
+        /// Creates a new CodedOutputStream that writes directly to the given
+        /// byte array slice. If more bytes are written than fit in the array,
+        /// OutOfSpaceException will be thrown.
+        /// </summary>
+        private CodedOutputStream(byte[] buffer, int offset, int length)
+        {
+            this.output = null;
+            this.buffer = buffer;
+            this.position = offset;
+            this.limit = offset + length;
+            leaveOpen = true; // Simple way of avoiding trying to dispose of a null reference
+        }
+
+        private CodedOutputStream(Stream output, byte[] buffer, bool leaveOpen)
+        {
+            this.output = ProtoPreconditions.CheckNotNull(output, "output");
+            this.buffer = buffer;
+            this.position = 0;
+            this.limit = buffer.Length;
+            this.leaveOpen = leaveOpen;
+        }
+
+        /// <summary>
+        /// Creates a new <see cref="CodedOutputStream" /> which write to the given stream, and disposes of that
+        /// stream when the returned <c>CodedOutputStream</c> is disposed.
+        /// </summary>
+        /// <param name="output">The stream to write to. It will be disposed when the returned <c>CodedOutputStream is disposed.</c></param>
+        public CodedOutputStream(Stream output) : this(output, DefaultBufferSize, false)
+        {
+        }
+
+        /// <summary>
+        /// Creates a new CodedOutputStream which write to the given stream and uses
+        /// the specified buffer size.
+        /// </summary>
+        /// <param name="output">The stream to write to. It will be disposed when the returned <c>CodedOutputStream is disposed.</c></param>
+        /// <param name="bufferSize">The size of buffer to use internally.</param>
+        public CodedOutputStream(Stream output, int bufferSize) : this(output, new byte[bufferSize], false)
+        {
+        }
+
+        /// <summary>
+        /// Creates a new CodedOutputStream which write to the given stream.
+        /// </summary>
+        /// <param name="output">The stream to write to.</param>
+        /// <param name="leaveOpen">If <c>true</c>, <paramref name="output"/> is left open when the returned <c>CodedOutputStream</c> is disposed;
+        /// if <c>false</c>, the provided stream is disposed as well.</param>
+        public CodedOutputStream(Stream output, bool leaveOpen) : this(output, DefaultBufferSize, leaveOpen)
+        {
+        }
+
+        /// <summary>
+        /// Creates a new CodedOutputStream which write to the given stream and uses
+        /// the specified buffer size.
+        /// </summary>
+        /// <param name="output">The stream to write to.</param>
+        /// <param name="bufferSize">The size of buffer to use internally.</param>
+        /// <param name="leaveOpen">If <c>true</c>, <paramref name="output"/> is left open when the returned <c>CodedOutputStream</c> is disposed;
+        /// if <c>false</c>, the provided stream is disposed as well.</param>
+        public CodedOutputStream(Stream output, int bufferSize, bool leaveOpen) : this(output, new byte[bufferSize], leaveOpen)
+        {
+        }
+        #endregion
+
+        /// <summary>
+        /// Returns the current position in the stream, or the position in the output buffer
+        /// </summary>
+        public long Position
+        {
+            get
+            {
+                if (output != null)
+                {
+                    return output.Position + position;
+                }
+                return position;
+            }
+        }
+
+        #region Writing of values (not including tags)
+
+        /// <summary>
+        /// Writes a double field value, without a tag, to the stream.
+        /// </summary>
+        /// <param name="value">The value to write</param>
+        public void WriteDouble(double value)
+        {
+            WriteRawLittleEndian64((ulong)BitConverter.DoubleToInt64Bits(value));
+        }
+
+        /// <summary>
+        /// Writes a float field value, without a tag, to the stream.
+        /// </summary>
+        /// <param name="value">The value to write</param>
+        public void WriteFloat(float value)
+        {
+            byte[] rawBytes = BitConverter.GetBytes(value);
+            if (!BitConverter.IsLittleEndian)
+            {
+                ByteArray.Reverse(rawBytes);
+            }
+
+            if (limit - position >= 4)
+            {
+                buffer[position++] = rawBytes[0];
+                buffer[position++] = rawBytes[1];
+                buffer[position++] = rawBytes[2];
+                buffer[position++] = rawBytes[3];
+            }
+            else
+            {
+                WriteRawBytes(rawBytes, 0, 4);
+            }
+        }
+
+        /// <summary>
+        /// Writes a uint64 field value, without a tag, to the stream.
+        /// </summary>
+        /// <param name="value">The value to write</param>
+        public void WriteUInt64(ulong value)
+        {
+            WriteRawVarint64(value);
+        }
+
+        /// <summary>
+        /// Writes an int64 field value, without a tag, to the stream.
+        /// </summary>
+        /// <param name="value">The value to write</param>
+        public void WriteInt64(long value)
+        {
+            WriteRawVarint64((ulong) value);
+        }
+
+        /// <summary>
+        /// Writes an int32 field value, without a tag, to the stream.
+        /// </summary>
+        /// <param name="value">The value to write</param>
+        public void WriteInt32(int value)
+        {
+            if (value >= 0)
+            {
+                WriteRawVarint32((uint) value);
+            }
+            else
+            {
+                // Must sign-extend.
+                WriteRawVarint64((ulong) value);
+            }
+        }
+
+        /// <summary>
+        /// Writes a fixed64 field value, without a tag, to the stream.
+        /// </summary>
+        /// <param name="value">The value to write</param>
+        public void WriteFixed64(ulong value)
+        {
+            WriteRawLittleEndian64(value);
+        }
+
+        /// <summary>
+        /// Writes a fixed32 field value, without a tag, to the stream.
+        /// </summary>
+        /// <param name="value">The value to write</param>
+        public void WriteFixed32(uint value)
+        {
+            WriteRawLittleEndian32(value);
+        }
+
+        /// <summary>
+        /// Writes a bool field value, without a tag, to the stream.
+        /// </summary>
+        /// <param name="value">The value to write</param>
+        public void WriteBool(bool value)
+        {
+            WriteRawByte(value ? (byte) 1 : (byte) 0);
+        }
+
+        /// <summary>
+        /// Writes a string field value, without a tag, to the stream.
+        /// The data is length-prefixed.
+        /// </summary>
+        /// <param name="value">The value to write</param>
+        public void WriteString(string value)
+        {
+            // Optimise the case where we have enough space to write
+            // the string directly to the buffer, which should be common.
+            int length = Utf8Encoding.GetByteCount(value);
+            WriteLength(length);
+            if (limit - position >= length)
+            {
+                if (length == value.Length) // Must be all ASCII...
+                {
+                    for (int i = 0; i < length; i++)
+                    {
+                        buffer[position + i] = (byte)value[i];
+                    }
+                }
+                else
+                {
+                    Utf8Encoding.GetBytes(value, 0, value.Length, buffer, position);
+                }
+                position += length;
+            }
+            else
+            {
+                byte[] bytes = Utf8Encoding.GetBytes(value);
+                WriteRawBytes(bytes);
+            }
+        }
+
+        /// <summary>
+        /// Writes a message, without a tag, to the stream.
+        /// The data is length-prefixed.
+        /// </summary>
+        /// <param name="value">The value to write</param>
+        public void WriteMessage(IMessage value)
+        {
+            WriteLength(value.CalculateSize());
+            value.WriteTo(this);
+        }
+
+        /// <summary>
+        /// Write a byte string, without a tag, to the stream.
+        /// The data is length-prefixed.
+        /// </summary>
+        /// <param name="value">The value to write</param>
+        public void WriteBytes(ByteString value)
+        {
+            WriteLength(value.Length);
+            value.WriteRawBytesTo(this);
+        }
+
+        /// <summary>
+        /// Writes a uint32 value, without a tag, to the stream.
+        /// </summary>
+        /// <param name="value">The value to write</param>
+        public void WriteUInt32(uint value)
+        {
+            WriteRawVarint32(value);
+        }
+
+        /// <summary>
+        /// Writes an enum value, without a tag, to the stream.
+        /// </summary>
+        /// <param name="value">The value to write</param>
+        public void WriteEnum(int value)
+        {
+            WriteInt32(value);
+        }
+
+        /// <summary>
+        /// Writes an sfixed32 value, without a tag, to the stream.
+        /// </summary>
+        /// <param name="value">The value to write.</param>
+        public void WriteSFixed32(int value)
+        {
+            WriteRawLittleEndian32((uint) value);
+        }
+
+        /// <summary>
+        /// Writes an sfixed64 value, without a tag, to the stream.
+        /// </summary>
+        /// <param name="value">The value to write</param>
+        public void WriteSFixed64(long value)
+        {
+            WriteRawLittleEndian64((ulong) value);
+        }
+
+        /// <summary>
+        /// Writes an sint32 value, without a tag, to the stream.
+        /// </summary>
+        /// <param name="value">The value to write</param>
+        public void WriteSInt32(int value)
+        {
+            WriteRawVarint32(EncodeZigZag32(value));
+        }
+
+        /// <summary>
+        /// Writes an sint64 value, without a tag, to the stream.
+        /// </summary>
+        /// <param name="value">The value to write</param>
+        public void WriteSInt64(long value)
+        {
+            WriteRawVarint64(EncodeZigZag64(value));
+        }
+
+        /// <summary>
+        /// Writes a length (in bytes) for length-delimited data.
+        /// </summary>
+        /// <remarks>
+        /// This method simply writes a rawint, but exists for clarity in calling code.
+        /// </remarks>
+        /// <param name="length">Length value, in bytes.</param>
+        public void WriteLength(int length)
+        {
+            WriteRawVarint32((uint) length);
+        }
+
+        #endregion
+
+        #region Raw tag writing
+        /// <summary>
+        /// Encodes and writes a tag.
+        /// </summary>
+        /// <param name="fieldNumber">The number of the field to write the tag for</param>
+        /// <param name="type">The wire format type of the tag to write</param>
+        public void WriteTag(int fieldNumber, WireFormat.WireType type)
+        {
+            WriteRawVarint32(WireFormat.MakeTag(fieldNumber, type));
+        }
+
+        /// <summary>
+        /// Writes an already-encoded tag.
+        /// </summary>
+        /// <param name="tag">The encoded tag</param>
+        public void WriteTag(uint tag)
+        {
+            WriteRawVarint32(tag);
+        }
+
+        /// <summary>
+        /// Writes the given single-byte tag directly to the stream.
+        /// </summary>
+        /// <param name="b1">The encoded tag</param>
+        public void WriteRawTag(byte b1)
+        {
+            WriteRawByte(b1);
+        }
+
+        /// <summary>
+        /// Writes the given two-byte tag directly to the stream.
+        /// </summary>
+        /// <param name="b1">The first byte of the encoded tag</param>
+        /// <param name="b2">The second byte of the encoded tag</param>
+        public void WriteRawTag(byte b1, byte b2)
+        {
+            WriteRawByte(b1);
+            WriteRawByte(b2);
+        }
+
+        /// <summary>
+        /// Writes the given three-byte tag directly to the stream.
+        /// </summary>
+        /// <param name="b1">The first byte of the encoded tag</param>
+        /// <param name="b2">The second byte of the encoded tag</param>
+        /// <param name="b3">The third byte of the encoded tag</param>
+        public void WriteRawTag(byte b1, byte b2, byte b3)
+        {
+            WriteRawByte(b1);
+            WriteRawByte(b2);
+            WriteRawByte(b3);
+        }
+
+        /// <summary>
+        /// Writes the given four-byte tag directly to the stream.
+        /// </summary>
+        /// <param name="b1">The first byte of the encoded tag</param>
+        /// <param name="b2">The second byte of the encoded tag</param>
+        /// <param name="b3">The third byte of the encoded tag</param>
+        /// <param name="b4">The fourth byte of the encoded tag</param>
+        public void WriteRawTag(byte b1, byte b2, byte b3, byte b4)
+        {
+            WriteRawByte(b1);
+            WriteRawByte(b2);
+            WriteRawByte(b3);
+            WriteRawByte(b4);
+        }
+
+        /// <summary>
+        /// Writes the given five-byte tag directly to the stream.
+        /// </summary>
+        /// <param name="b1">The first byte of the encoded tag</param>
+        /// <param name="b2">The second byte of the encoded tag</param>
+        /// <param name="b3">The third byte of the encoded tag</param>
+        /// <param name="b4">The fourth byte of the encoded tag</param>
+        /// <param name="b5">The fifth byte of the encoded tag</param>
+        public void WriteRawTag(byte b1, byte b2, byte b3, byte b4, byte b5)
+        {
+            WriteRawByte(b1);
+            WriteRawByte(b2);
+            WriteRawByte(b3);
+            WriteRawByte(b4);
+            WriteRawByte(b5);
+        }
+        #endregion
+
+        #region Underlying writing primitives
+        /// <summary>
+        /// Writes a 32 bit value as a varint. The fast route is taken when
+        /// there's enough buffer space left to whizz through without checking
+        /// for each byte; otherwise, we resort to calling WriteRawByte each time.
+        /// </summary>
+        internal void WriteRawVarint32(uint value)
+        {
+            // Optimize for the common case of a single byte value
+            if (value < 128 && position < limit)
+            {
+                buffer[position++] = (byte)value;
+                return;
+            }
+
+            while (value > 127 && position < limit)
+            {
+                buffer[position++] = (byte) ((value & 0x7F) | 0x80);
+                value >>= 7;
+            }
+            while (value > 127)
+            {
+                WriteRawByte((byte) ((value & 0x7F) | 0x80));
+                value >>= 7;
+            }
+            if (position < limit)
+            {
+                buffer[position++] = (byte) value;
+            }
+            else
+            {
+                WriteRawByte((byte) value);
+            }
+        }
+
+        internal void WriteRawVarint64(ulong value)
+        {
+            while (value > 127 && position < limit)
+            {
+                buffer[position++] = (byte) ((value & 0x7F) | 0x80);
+                value >>= 7;
+            }
+            while (value > 127)
+            {
+                WriteRawByte((byte) ((value & 0x7F) | 0x80));
+                value >>= 7;
+            }
+            if (position < limit)
+            {
+                buffer[position++] = (byte) value;
+            }
+            else
+            {
+                WriteRawByte((byte) value);
+            }
+        }
+
+        internal void WriteRawLittleEndian32(uint value)
+        {
+            if (position + 4 > limit)
+            {
+                WriteRawByte((byte) value);
+                WriteRawByte((byte) (value >> 8));
+                WriteRawByte((byte) (value >> 16));
+                WriteRawByte((byte) (value >> 24));
+            }
+            else
+            {
+                buffer[position++] = ((byte) value);
+                buffer[position++] = ((byte) (value >> 8));
+                buffer[position++] = ((byte) (value >> 16));
+                buffer[position++] = ((byte) (value >> 24));
+            }
+        }
+
+        internal void WriteRawLittleEndian64(ulong value)
+        {
+            if (position + 8 > limit)
+            {
+                WriteRawByte((byte) value);
+                WriteRawByte((byte) (value >> 8));
+                WriteRawByte((byte) (value >> 16));
+                WriteRawByte((byte) (value >> 24));
+                WriteRawByte((byte) (value >> 32));
+                WriteRawByte((byte) (value >> 40));
+                WriteRawByte((byte) (value >> 48));
+                WriteRawByte((byte) (value >> 56));
+            }
+            else
+            {
+                buffer[position++] = ((byte) value);
+                buffer[position++] = ((byte) (value >> 8));
+                buffer[position++] = ((byte) (value >> 16));
+                buffer[position++] = ((byte) (value >> 24));
+                buffer[position++] = ((byte) (value >> 32));
+                buffer[position++] = ((byte) (value >> 40));
+                buffer[position++] = ((byte) (value >> 48));
+                buffer[position++] = ((byte) (value >> 56));
+            }
+        }
+
+        internal void WriteRawByte(byte value)
+        {
+            if (position == limit)
+            {
+                RefreshBuffer();
+            }
+
+            buffer[position++] = value;
+        }
+
+        internal void WriteRawByte(uint value)
+        {
+            WriteRawByte((byte) value);
+        }
+
+        /// <summary>
+        /// Writes out an array of bytes.
+        /// </summary>
+        internal void WriteRawBytes(byte[] value)
+        {
+            WriteRawBytes(value, 0, value.Length);
+        }
+
+        /// <summary>
+        /// Writes out part of an array of bytes.
+        /// </summary>
+        internal void WriteRawBytes(byte[] value, int offset, int length)
+        {
+            if (limit - position >= length)
+            {
+                ByteArray.Copy(value, offset, buffer, position, length);
+                // We have room in the current buffer.
+                position += length;
+            }
+            else
+            {
+                // Write extends past current buffer.  Fill the rest of this buffer and
+                // flush.
+                int bytesWritten = limit - position;
+                ByteArray.Copy(value, offset, buffer, position, bytesWritten);
+                offset += bytesWritten;
+                length -= bytesWritten;
+                position = limit;
+                RefreshBuffer();
+
+                // Now deal with the rest.
+                // Since we have an output stream, this is our buffer
+                // and buffer offset == 0
+                if (length <= limit)
+                {
+                    // Fits in new buffer.
+                    ByteArray.Copy(value, offset, buffer, 0, length);
+                    position = length;
+                }
+                else
+                {
+                    // Write is very big.  Let's do it all at once.
+                    output.Write(value, offset, length);
+                }
+            }
+        }
+
+        #endregion
+
+        /// <summary>
+        /// Encode a 32-bit value with ZigZag encoding.
+        /// </summary>
+        /// <remarks>
+        /// ZigZag encodes signed integers into values that can be efficiently
+        /// encoded with varint.  (Otherwise, negative values must be 
+        /// sign-extended to 64 bits to be varint encoded, thus always taking
+        /// 10 bytes on the wire.)
+        /// </remarks>
+        internal static uint EncodeZigZag32(int n)
+        {
+            // Note:  the right-shift must be arithmetic
+            return (uint) ((n << 1) ^ (n >> 31));
+        }
+
+        /// <summary>
+        /// Encode a 64-bit value with ZigZag encoding.
+        /// </summary>
+        /// <remarks>
+        /// ZigZag encodes signed integers into values that can be efficiently
+        /// encoded with varint.  (Otherwise, negative values must be 
+        /// sign-extended to 64 bits to be varint encoded, thus always taking
+        /// 10 bytes on the wire.)
+        /// </remarks>
+        internal static ulong EncodeZigZag64(long n)
+        {
+            return (ulong) ((n << 1) ^ (n >> 63));
+        }
+
+        private void RefreshBuffer()
+        {
+            if (output == null)
+            {
+                // We're writing to a single buffer.
+                throw new OutOfSpaceException();
+            }
+
+            // Since we have an output stream, this is our buffer
+            // and buffer offset == 0
+            output.Write(buffer, 0, position);
+            position = 0;
+        }
+
+        /// <summary>
+        /// Indicates that a CodedOutputStream wrapping a flat byte array
+        /// ran out of space.
+        /// </summary>
+        public sealed class OutOfSpaceException : IOException
+        {
+            internal OutOfSpaceException()
+                : base("CodedOutputStream was writing to a flat byte array and ran out of space.")
+            {
+            }
+        }
+
+        /// <summary>
+        /// Flushes any buffered data and optionally closes the underlying stream, if any.
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// By default, any underlying stream is closed by this method. To configure this behaviour,
+        /// use a constructor overload with a <c>leaveOpen</c> parameter. If this instance does not
+        /// have an underlying stream, this method does nothing.
+        /// </para>
+        /// <para>
+        /// For the sake of efficiency, calling this method does not prevent future write calls - but
+        /// if a later write ends up writing to a stream which has been disposed, that is likely to
+        /// fail. It is recommend that you not call any other methods after this.
+        /// </para>
+        /// </remarks>
+        public void Dispose()
+        {
+            Flush();
+            if (!leaveOpen)
+            {
+                output.Dispose();
+            }
+        }
+
+        /// <summary>
+        /// Flushes any buffered data to the underlying stream (if there is one).
+        /// </summary>
+        public void Flush()
+        {
+            if (output != null)
+            {
+                RefreshBuffer();
+            }
+        }
+
+        /// <summary>
+        /// Verifies that SpaceLeft returns zero. It's common to create a byte array
+        /// that is exactly big enough to hold a message, then write to it with
+        /// a CodedOutputStream. Calling CheckNoSpaceLeft after writing verifies that
+        /// the message was actually as big as expected, which can help bugs.
+        /// </summary>
+        public void CheckNoSpaceLeft()
+        {
+            if (SpaceLeft != 0)
+            {
+                throw new InvalidOperationException("Did not write as much data as expected.");
+            }
+        }
+
+        /// <summary>
+        /// If writing to a flat array, returns the space left in the array. Otherwise,
+        /// throws an InvalidOperationException.
+        /// </summary>
+        public int SpaceLeft
+        {
+            get
+            {
+                if (output == null)
+                {
+                    return limit - position;
+                }
+                else
+                {
+                    throw new InvalidOperationException(
+                        "SpaceLeft can only be called on CodedOutputStreams that are " +
+                        "writing to a flat array.");
+                }
+            }
+        }
+    }
+}

+ 11 - 0
Unity/Assets/ThirdParty/Google.Protobuf/CodedOutputStream.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e4768e92c8082c14db86e6dd81843cf7
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 2 - 3
Unity/Assets/ThirdParty/Protobuf/Editor.meta → Unity/Assets/ThirdParty/Google.Protobuf/Collections.meta

@@ -1,9 +1,8 @@
 fileFormatVersion: 2
-guid: c089ef16fa1b4b944a448e2da307bc74
+guid: a10213e3b8b8c674b9390af03e71deb8
 folderAsset: yes
-timeCreated: 1517401476
-licenseType: Free
 DefaultImporter:
+  externalObjects: {}
   userData: 
   assetBundleName: 
   assetBundleVariant: 

+ 580 - 0
Unity/Assets/ThirdParty/Google.Protobuf/Collections/RepeatedField.cs

@@ -0,0 +1,580 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+
+namespace Google.Protobuf.Collections
+{
+    /// <summary>
+    /// The contents of a repeated field: essentially, a collection with some extra
+    /// restrictions (no null values) and capabilities (deep cloning).
+    /// </summary>
+    /// <remarks>
+    /// This implementation does not generally prohibit the use of types which are not
+    /// supported by Protocol Buffers but nor does it guarantee that all operations will work in such cases.
+    /// </remarks>
+    /// <typeparam name="T">The element type of the repeated field.</typeparam>
+    public sealed class RepeatedField<T> : IList<T>, IList 
+    {
+        private static readonly T[] EmptyArray = new T[0];
+        private const int MinArraySize = 8;
+
+        public T[] array = EmptyArray;
+        public int count = 0;
+
+        /// <summary>
+        /// Adds the entries from the given input stream, decoding them with the specified codec.
+        /// </summary>
+        /// <param name="input">The input stream to read from.</param>
+        /// <param name="codec">The codec to use in order to read each entry.</param>
+        public void AddEntriesFrom(CodedInputStream input, FieldCodec<T> codec)
+        {
+            // TODO: Inline some of the Add code, so we can avoid checking the size on every
+            // iteration.
+            uint tag = input.LastTag;
+            var reader = codec.ValueReader;
+            // Non-nullable value types can be packed or not.
+            if (FieldCodec<T>.IsPackedRepeatedField(tag))
+            {
+                int length = input.ReadLength();
+                if (length > 0)
+                {
+                    int oldLimit = input.PushLimit(length);
+                    while (!input.ReachedLimit)
+                    {
+                        Add(reader(input));
+                    }
+                    input.PopLimit(oldLimit);
+                }
+                // Empty packed field. Odd, but valid - just ignore.
+            }
+            else
+            {
+                // Not packed... (possibly not packable)
+                do
+                {
+                    Add(reader(input));
+                } while (input.MaybeConsumeTag(tag));
+            }
+        }
+
+        /// <summary>
+        /// Calculates the size of this collection based on the given codec.
+        /// </summary>
+        /// <param name="codec">The codec to use when encoding each field.</param>
+        /// <returns>The number of bytes that would be written to a <see cref="CodedOutputStream"/> by <see cref="WriteTo"/>,
+        /// using the same codec.</returns>
+        public int CalculateSize(FieldCodec<T> codec)
+        {
+            if (count == 0)
+            {
+                return 0;
+            }
+            uint tag = codec.Tag;
+            if (codec.PackedRepeatedField)
+            {
+                int dataSize = CalculatePackedDataSize(codec);
+                return CodedOutputStream.ComputeRawVarint32Size(tag) +
+                    CodedOutputStream.ComputeLengthSize(dataSize) +
+                    dataSize;
+            }
+            else
+            {
+                var sizeCalculator = codec.ValueSizeCalculator;
+                int size = count * CodedOutputStream.ComputeRawVarint32Size(tag);
+                for (int i = 0; i < count; i++)
+                {
+                    size += sizeCalculator(array[i]);
+                }
+                return size;
+            }
+        }
+
+        private int CalculatePackedDataSize(FieldCodec<T> codec)
+        {
+            int fixedSize = codec.FixedSize;
+            if (fixedSize == 0)
+            {
+                var calculator = codec.ValueSizeCalculator;
+                int tmp = 0;
+                for (int i = 0; i < count; i++)
+                {
+                    tmp += calculator(array[i]);
+                }
+                return tmp;
+            }
+            else
+            {
+                return fixedSize * Count;
+            }
+        }
+
+        /// <summary>
+        /// Writes the contents of this collection to the given <see cref="CodedOutputStream"/>,
+        /// encoding each value using the specified codec.
+        /// </summary>
+        /// <param name="output">The output stream to write to.</param>
+        /// <param name="codec">The codec to use when encoding each value.</param>
+        public void WriteTo(CodedOutputStream output, FieldCodec<T> codec)
+        {
+            if (count == 0)
+            {
+                return;
+            }
+            var writer = codec.ValueWriter;
+            var tag = codec.Tag;
+            if (codec.PackedRepeatedField)
+            {
+                // Packed primitive type
+                uint size = (uint)CalculatePackedDataSize(codec);
+                output.WriteTag(tag);
+                output.WriteRawVarint32(size);
+                for (int i = 0; i < count; i++)
+                {
+                    writer(output, array[i]);
+                }
+            }
+            else
+            {
+                // Not packed: a simple tag/value pair for each value.
+                // Can't use codec.WriteTagAndValue, as that omits default values.
+                for (int i = 0; i < count; i++)
+                {
+                    output.WriteTag(tag);
+                    writer(output, array[i]);
+                }
+            }
+        }
+
+        private void EnsureSize(int size)
+        {
+            if (array.Length < size)
+            {
+                size = Math.Max(size, MinArraySize);
+                int newSize = Math.Max(array.Length * 2, size);
+                var tmp = new T[newSize];
+                Array.Copy(array, 0, tmp, 0, array.Length);
+                array = tmp;
+            }
+        }
+
+        /// <summary>
+        /// Adds the specified item to the collection.
+        /// </summary>
+        /// <param name="item">The item to add.</param>
+        public void Add(T item)
+        {
+            ProtoPreconditions.CheckNotNullUnconstrained(item, "item");
+            EnsureSize(count + 1);
+            array[count++] = item;
+        }
+
+        /// <summary>
+        /// Removes all items from the collection.
+        /// </summary>
+        public void Clear()
+        {
+            array = EmptyArray;
+            count = 0;
+        }
+
+        /// <summary>
+        /// Determines whether this collection contains the given item.
+        /// </summary>
+        /// <param name="item">The item to find.</param>
+        /// <returns><c>true</c> if this collection contains the given item; <c>false</c> otherwise.</returns>
+        public bool Contains(T item)
+        {
+            return IndexOf(item) != -1;
+        }
+
+        /// <summary>
+        /// Copies this collection to the given array.
+        /// </summary>
+        /// <param name="array">The array to copy to.</param>
+        /// <param name="arrayIndex">The first index of the array to copy to.</param>
+        public void CopyTo(T[] array, int arrayIndex)
+        {
+            Array.Copy(this.array, 0, array, arrayIndex, count);
+        }
+
+        /// <summary>
+        /// Removes the specified item from the collection
+        /// </summary>
+        /// <param name="item">The item to remove.</param>
+        /// <returns><c>true</c> if the item was found and removed; <c>false</c> otherwise.</returns>
+        public bool Remove(T item)
+        {
+            int index = IndexOf(item);
+            if (index == -1)
+            {
+                return false;
+            }
+            Array.Copy(array, index + 1, array, index, count - index - 1);
+            count--;
+            array[count] = default(T);
+            return true;
+        }
+
+        /// <summary>
+        /// Gets the number of elements contained in the collection.
+        /// </summary>
+        public int Count
+        {
+            get
+            {
+                return count;
+            }
+        }
+
+        /// <summary>
+        /// Gets a value indicating whether the collection is read-only.
+        /// </summary>
+        public bool IsReadOnly
+        {
+            get
+            {
+                return false;
+            }
+        }
+
+        /// <summary>
+        /// Adds all of the specified values into this collection.
+        /// </summary>
+        /// <param name="values">The values to add to this collection.</param>
+        public void AddRange(IEnumerable<T> values)
+        {
+            ProtoPreconditions.CheckNotNull(values, "values");
+
+            // Optimization 1: If the collection we're adding is already a RepeatedField<T>,
+            // we know the values are valid.
+            var otherRepeatedField = values as RepeatedField<T>;
+            if (otherRepeatedField != null)
+            {
+                EnsureSize(count + otherRepeatedField.count);
+                Array.Copy(otherRepeatedField.array, 0, array, count, otherRepeatedField.count);
+                count += otherRepeatedField.count;
+                return;
+            }
+
+            // Optimization 2: The collection is an ICollection, so we can expand
+            // just once and ask the collection to copy itself into the array.
+            var collection = values as ICollection;
+            if (collection != null)
+            {
+                var extraCount = collection.Count;
+                // For reference types and nullable value types, we need to check that there are no nulls
+                // present. (This isn't a thread-safe approach, but we don't advertise this is thread-safe.)
+                // We expect the JITter to optimize this test to true/false, so it's effectively conditional
+                // specialization.
+                if (default(T) == null)
+                {
+                    // TODO: Measure whether iterating once to check and then letting the collection copy
+                    // itself is faster or slower than iterating and adding as we go. For large
+                    // collections this will not be great in terms of cache usage... but the optimized
+                    // copy may be significantly faster than doing it one at a time.
+                    foreach (var item in collection)
+                    {
+                        if (item == null)
+                        {
+                            throw new ArgumentException("Sequence contained null element", "values");
+                        }
+                    }
+                }
+                EnsureSize(count + extraCount);
+                collection.CopyTo(array, count);
+                count += extraCount;
+                return;
+            }
+
+            // We *could* check for ICollection<T> as well, but very very few collections implement
+            // ICollection<T> but not ICollection. (HashSet<T> does, for one...)
+
+            // Fall back to a slower path of adding items one at a time.
+            foreach (T item in values)
+            {
+                Add(item);
+            }
+        }
+
+        /// <summary>
+        /// Adds all of the specified values into this collection. This method is present to
+        /// allow repeated fields to be constructed from queries within collection initializers.
+        /// Within non-collection-initializer code, consider using the equivalent <see cref="AddRange"/>
+        /// method instead for clarity.
+        /// </summary>
+        /// <param name="values">The values to add to this collection.</param>
+        public void Add(IEnumerable<T> values)
+        {
+            AddRange(values);
+        }
+
+        /// <summary>
+        /// Returns an enumerator that iterates through the collection.
+        /// </summary>
+        /// <returns>
+        /// An enumerator that can be used to iterate through the collection.
+        /// </returns>
+        public IEnumerator<T> GetEnumerator()
+        {
+            for (int i = 0; i < count; i++)
+            {
+                yield return array[i];
+            }
+        }
+
+        /// <summary>
+        /// Determines whether the specified <see cref="System.Object" />, is equal to this instance.
+        /// </summary>
+        /// <param name="obj">The <see cref="System.Object" /> to compare with this instance.</param>
+        /// <returns>
+        ///   <c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.
+        /// </returns>
+        public override bool Equals(object obj)
+        {
+            return Equals(obj as RepeatedField<T>);
+        }
+
+        /// <summary>
+        /// Returns an enumerator that iterates through a collection.
+        /// </summary>
+        /// <returns>
+        /// An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.
+        /// </returns>
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return GetEnumerator();
+        }
+
+        /// <summary>
+        /// Returns a hash code for this instance.
+        /// </summary>
+        /// <returns>
+        /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 
+        /// </returns>
+        public override int GetHashCode()
+        {
+            int hash = 0;
+            for (int i = 0; i < count; i++)
+            {
+                hash = hash * 31 + array[i].GetHashCode();
+            }
+            return hash;
+        }
+
+        /// <summary>
+        /// Compares this repeated field with another for equality.
+        /// </summary>
+        /// <param name="other">The repeated field to compare this with.</param>
+        /// <returns><c>true</c> if <paramref name="other"/> refers to an equal repeated field; <c>false</c> otherwise.</returns>
+        public bool Equals(RepeatedField<T> other)
+        {
+            if (ReferenceEquals(other, null))
+            {
+                return false;
+            }
+            if (ReferenceEquals(other, this))
+            {
+                return true;
+            }
+            if (other.Count != this.Count)
+            {
+                return false;
+            }
+            EqualityComparer<T> comparer = EqualityComparer<T>.Default;
+            for (int i = 0; i < count; i++)
+            {
+                if (!comparer.Equals(array[i], other.array[i]))
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        /// <summary>
+        /// Returns the index of the given item within the collection, or -1 if the item is not
+        /// present.
+        /// </summary>
+        /// <param name="item">The item to find in the collection.</param>
+        /// <returns>The zero-based index of the item, or -1 if it is not found.</returns>
+        public int IndexOf(T item)
+        {
+            ProtoPreconditions.CheckNotNullUnconstrained(item, "item");
+            EqualityComparer<T> comparer = EqualityComparer<T>.Default;
+            for (int i = 0; i < count; i++)
+            {
+                if (comparer.Equals(array[i], item))
+                {
+                    return i;
+                }
+            }
+            return -1;
+        }
+
+        /// <summary>
+        /// Inserts the given item at the specified index.
+        /// </summary>
+        /// <param name="index">The index at which to insert the item.</param>
+        /// <param name="item">The item to insert.</param>
+        public void Insert(int index, T item)
+        {
+            ProtoPreconditions.CheckNotNullUnconstrained(item, "item");
+            if (index < 0 || index > count)
+            {
+                throw new ArgumentOutOfRangeException("index");
+            }
+            EnsureSize(count + 1);
+            Array.Copy(array, index, array, index + 1, count - index);
+            array[index] = item;
+            count++;
+        }
+
+        /// <summary>
+        /// Removes the item at the given index.
+        /// </summary>
+        /// <param name="index">The zero-based index of the item to remove.</param>
+        public void RemoveAt(int index)
+        {
+            if (index < 0 || index >= count)
+            {
+                throw new ArgumentOutOfRangeException("index");
+            }
+            Array.Copy(array, index + 1, array, index, count - index - 1);
+            count--;
+            array[count] = default(T);
+        }
+
+        /// <summary>
+        /// Gets or sets the item at the specified index.
+        /// </summary>
+        /// <value>
+        /// The element at the specified index.
+        /// </value>
+        /// <param name="index">The zero-based index of the element to get or set.</param>
+        /// <returns>The item at the specified index.</returns>
+        public T this[int index]
+        {
+            get
+            {
+                if (index < 0 || index >= count)
+                {
+                    throw new ArgumentOutOfRangeException("index");
+                }
+                return array[index];
+            }
+            set
+            {
+                if (index < 0 || index >= count)
+                {
+                    throw new ArgumentOutOfRangeException("index");
+                }
+                ProtoPreconditions.CheckNotNullUnconstrained(value, "value");
+                array[index] = value;
+            }
+        }
+
+        #region Explicit interface implementation for IList and ICollection.
+        bool IList.IsFixedSize
+        {
+            get
+            {
+                return false;
+            }
+        }
+
+        void ICollection.CopyTo(Array array, int index)
+        {
+            Array.Copy(this.array, 0, array, index, count);
+        }
+
+        bool ICollection.IsSynchronized
+        {
+            get
+            {
+                return false;
+            }
+        }
+
+        object ICollection.SyncRoot
+        {
+            get
+            {
+                return this;
+            }
+        }
+
+        object IList.this[int index]
+        {
+            get { return this[index]; }
+            set { this[index] = (T)value; }
+        }
+
+        int IList.Add(object value)
+        {
+            Add((T)value);
+            return count - 1;
+        }
+
+        bool IList.Contains(object value)
+        {
+            return (value is T && Contains((T)value));
+        }
+
+        int IList.IndexOf(object value)
+        {
+            if (!(value is T))
+            {
+                return -1;
+            }
+            return IndexOf((T)value);
+        }
+
+        void IList.Insert(int index, object value)
+        {
+            Insert(index, (T)value);
+        }
+
+        void IList.Remove(object value)
+        {
+            if (!(value is T))
+            {
+                return;
+            }
+            Remove((T)value);
+        }
+        #endregion        
+    }
+}

+ 11 - 0
Unity/Assets/ThirdParty/Google.Protobuf/Collections/RepeatedField.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 462fd9852b348c34094dbb0e82649335
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 2 - 3
Unity/Assets/ThirdParty/Protobuf/protobuf-net.meta → Unity/Assets/ThirdParty/Google.Protobuf/Compatibility.meta

@@ -1,9 +1,8 @@
 fileFormatVersion: 2
-guid: 7e3f7b5d5d9676f41a4e50538fcade57
+guid: cfb7fc188ca11b7408a21d310543397c
 folderAsset: yes
-timeCreated: 1517401476
-licenseType: Free
 DefaultImporter:
+  externalObjects: {}
   userData: 
   assetBundleName: 
   assetBundleVariant: 

+ 64 - 0
Unity/Assets/ThirdParty/Google.Protobuf/Compatibility/PropertyInfoExtensions.cs

@@ -0,0 +1,64 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System.Reflection;
+
+namespace Google.Protobuf.Compatibility
+{
+    /// <summary>
+    /// Extension methods for <see cref="PropertyInfo"/>, effectively providing
+    /// the familiar members from previous desktop framework versions while
+    /// targeting the newer releases, .NET Core etc.
+    /// </summary>
+    internal static class PropertyInfoExtensions
+    {
+        /// <summary>
+        /// Returns the public getter of a property, or null if there is no such getter
+        /// (either because it's read-only, or the getter isn't public).
+        /// </summary>
+        internal static MethodInfo GetGetMethod(this PropertyInfo target)
+        {
+            var method = target.GetGetMethod();
+            return method != null && method.IsPublic ? method : null;
+        }
+
+        /// <summary>
+        /// Returns the public setter of a property, or null if there is no such setter
+        /// (either because it's write-only, or the setter isn't public).
+        /// </summary>
+        internal static MethodInfo GetSetMethod(this PropertyInfo target)
+        {
+            var method = target.GetSetMethod();
+            return method != null && method.IsPublic ? method : null;
+        }
+    }
+}

+ 11 - 0
Unity/Assets/ThirdParty/Google.Protobuf/Compatibility/PropertyInfoExtensions.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a1ba303b1b8d9d943a4c0189a878a77f
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 64 - 0
Unity/Assets/ThirdParty/Google.Protobuf/Compatibility/StreamExtensions.cs

@@ -0,0 +1,64 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.IO;
+
+namespace Google.Protobuf.Compatibility
+{
+    /// <summary>
+    /// Extension methods for <see cref="Stream"/> in order to provide
+    /// backwards compatibility with .NET 3.5
+    /// </summary>
+    public static class StreamExtensions
+    {
+        // 81920 seems to be the default buffer size used in .NET 4.5.1
+        private const int BUFFER_SIZE = 81920;
+
+        /// <summary>
+        /// Write the contents of the current stream to the destination stream
+        /// </summary>
+        public static void CopyTo(this Stream source, Stream destination)
+        {
+            if (destination == null)
+            {
+                throw new ArgumentNullException("destination");
+            }
+
+            byte[] buffer = new byte[BUFFER_SIZE];
+            int numBytesRead;
+            while ((numBytesRead = source.Read(buffer, 0, buffer.Length)) > 0) {
+                destination.Write(buffer, 0, numBytesRead);
+            }
+        }
+    }
+}

+ 11 - 0
Unity/Assets/ThirdParty/Google.Protobuf/Compatibility/StreamExtensions.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 51467fdc5aeb0374baba8cb484d68f4c
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 379 - 0
Unity/Assets/ThirdParty/Google.Protobuf/FieldCodec.cs

@@ -0,0 +1,379 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Factory methods for <see cref="FieldCodec{T}"/>.
+    /// </summary>
+    public static class FieldCodec
+    {
+        // TODO: Avoid the "dual hit" of lambda expressions: create open delegates instead. (At least test...)
+
+        /// <summary>
+        /// Retrieves a codec suitable for a string field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<string> ForString(uint tag)
+        {
+            return new FieldCodec<string>(input => input.ReadString(), (output, value) => output.WriteString(value), CodedOutputStream.ComputeStringSize, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a bytes field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<ByteString> ForBytes(uint tag)
+        {
+            return new FieldCodec<ByteString>(input => input.ReadBytes(), (output, value) => output.WriteBytes(value), CodedOutputStream.ComputeBytesSize, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a bool field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<bool> ForBool(uint tag)
+        {
+            return new FieldCodec<bool>(input => input.ReadBool(), (output, value) => output.WriteBool(value), CodedOutputStream.ComputeBoolSize, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for an int32 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<int> ForInt32(uint tag)
+        {
+            return new FieldCodec<int>(input => input.ReadInt32(), (output, value) => output.WriteInt32(value), CodedOutputStream.ComputeInt32Size, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for an sint32 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<int> ForSInt32(uint tag)
+        {
+            return new FieldCodec<int>(input => input.ReadSInt32(), (output, value) => output.WriteSInt32(value), CodedOutputStream.ComputeSInt32Size, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a fixed32 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<uint> ForFixed32(uint tag)
+        {
+            return new FieldCodec<uint>(input => input.ReadFixed32(), (output, value) => output.WriteFixed32(value), 4, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for an sfixed32 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<int> ForSFixed32(uint tag)
+        {
+            return new FieldCodec<int>(input => input.ReadSFixed32(), (output, value) => output.WriteSFixed32(value), 4, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a uint32 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<uint> ForUInt32(uint tag)
+        {
+            return new FieldCodec<uint>(input => input.ReadUInt32(), (output, value) => output.WriteUInt32(value), CodedOutputStream.ComputeUInt32Size, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for an int64 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<long> ForInt64(uint tag)
+        {
+            return new FieldCodec<long>(input => input.ReadInt64(), (output, value) => output.WriteInt64(value), CodedOutputStream.ComputeInt64Size, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for an sint64 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<long> ForSInt64(uint tag)
+        {
+            return new FieldCodec<long>(input => input.ReadSInt64(), (output, value) => output.WriteSInt64(value), CodedOutputStream.ComputeSInt64Size, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a fixed64 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<ulong> ForFixed64(uint tag)
+        {
+            return new FieldCodec<ulong>(input => input.ReadFixed64(), (output, value) => output.WriteFixed64(value), 8, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for an sfixed64 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<long> ForSFixed64(uint tag)
+        {
+            return new FieldCodec<long>(input => input.ReadSFixed64(), (output, value) => output.WriteSFixed64(value), 8, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a uint64 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<ulong> ForUInt64(uint tag)
+        {
+            return new FieldCodec<ulong>(input => input.ReadUInt64(), (output, value) => output.WriteUInt64(value), CodedOutputStream.ComputeUInt64Size, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a float field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<float> ForFloat(uint tag)
+        {
+            return new FieldCodec<float>(input => input.ReadFloat(), (output, value) => output.WriteFloat(value), CodedOutputStream.ComputeFloatSize, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a double field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<double> ForDouble(uint tag)
+        {
+            return new FieldCodec<double>(input => input.ReadDouble(), (output, value) => output.WriteDouble(value), CodedOutputStream.ComputeDoubleSize, tag);
+        }
+
+        // Enums are tricky. We can probably use expression trees to build these delegates automatically,
+        // but it's easy to generate the code for it.
+
+        /// <summary>
+        /// Retrieves a codec suitable for an enum field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <param name="toInt32">A conversion function from <see cref="Int32"/> to the enum type.</param>
+        /// <param name="fromInt32">A conversion function from the enum type to <see cref="Int32"/>.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<T> ForEnum<T>(uint tag, Func<T, int> toInt32, Func<int, T> fromInt32)
+        {
+            return new FieldCodec<T>(input => fromInt32(
+                input.ReadEnum()),
+                (output, value) => output.WriteEnum(toInt32(value)),
+                value => CodedOutputStream.ComputeEnumSize(toInt32(value)), tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a message field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <param name="parser">A parser to use for the message type.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<T> ForMessage<T>(uint tag, MessageParser<T> parser) where T : IMessage
+        {
+            return new FieldCodec<T>(input => { T message = parser.CreateTemplate(); input.ReadMessage(message); return message; },
+                (output, value) => output.WriteMessage(value), message => CodedOutputStream.ComputeMessageSize(message), tag);
+        }
+    }
+
+    /// <summary>
+    /// <para>
+    /// An encode/decode pair for a single field. This effectively encapsulates
+    /// all the information needed to read or write the field value from/to a coded
+    /// stream.
+    /// </para>
+    /// <para>
+    /// This class is public and has to be as it is used by generated code, but its public
+    /// API is very limited - just what the generated code needs to call directly.
+    /// </para>
+    /// </summary>
+    /// <remarks>
+    /// This never writes default values to the stream, and does not address "packedness"
+    /// in repeated fields itself, other than to know whether or not the field *should* be packed.
+    /// </remarks>
+    public sealed class FieldCodec<T>
+    {
+        private static readonly T DefaultDefault;
+        // Only non-nullable value types support packing. This is the simplest way of detecting that.
+        private static readonly bool TypeSupportsPacking = default(T) != null;
+
+        static FieldCodec()
+        {
+            if (typeof(T) == typeof(string))
+            {
+                DefaultDefault = (T)(object)"";
+            }
+            else if (typeof(T) == typeof(ByteString))
+            {
+                DefaultDefault = (T)(object)ByteString.Empty;
+            }
+            // Otherwise it's the default value of the CLR type
+        }
+
+        internal static bool IsPackedRepeatedField(uint tag)
+        {
+            return TypeSupportsPacking && WireFormat.GetTagWireType(tag) == WireFormat.WireType.LengthDelimited;
+        }
+
+        internal readonly bool PackedRepeatedField;
+
+        /// <summary>
+        /// Returns a delegate to write a value (unconditionally) to a coded output stream.
+        /// </summary>
+        internal readonly Action<CodedOutputStream, T> ValueWriter;
+
+        /// <summary>
+        /// Returns the size calculator for just a value.
+        /// </summary>
+        internal readonly Func<T, int> ValueSizeCalculator;
+
+        /// <summary>
+        /// Returns a delegate to read a value from a coded input stream. It is assumed that
+        /// the stream is already positioned on the appropriate tag.
+        /// </summary>
+        internal readonly Func<CodedInputStream, T> ValueReader;
+
+        /// <summary>
+        /// Returns the fixed size for an entry, or 0 if sizes vary.
+        /// </summary>
+        internal readonly int FixedSize;
+
+        /// <summary>
+        /// Gets the tag of the codec.
+        /// </summary>
+        /// <value>
+        /// The tag of the codec.
+        /// </value>
+        internal readonly uint Tag;
+
+        /// <summary>
+        /// Default value for this codec. Usually the same for every instance of the same type, but
+        /// for string/ByteString wrapper fields the codec's default value is null, whereas for
+        /// other string/ByteString fields it's "" or ByteString.Empty.
+        /// </summary>
+        /// <value>
+        /// The default value of the codec's type.
+        /// </value>
+        internal readonly T DefaultValue;
+
+        private readonly int tagSize;
+        
+        internal FieldCodec(
+                Func<CodedInputStream, T> reader,
+                Action<CodedOutputStream, T> writer,
+                int fixedSize,
+                uint tag) : this(reader, writer, _ => fixedSize, tag)
+        {
+            FixedSize = fixedSize;
+        }
+
+        internal FieldCodec(
+            Func<CodedInputStream, T> reader,
+            Action<CodedOutputStream, T> writer,
+            Func<T, int> sizeCalculator,
+            uint tag) : this(reader, writer, sizeCalculator, tag, DefaultDefault)
+        {
+        }
+
+        internal FieldCodec(
+            Func<CodedInputStream, T> reader,
+            Action<CodedOutputStream, T> writer,
+            Func<T, int> sizeCalculator,
+            uint tag,
+            T defaultValue)
+        {
+            ValueReader = reader;
+            ValueWriter = writer;
+            ValueSizeCalculator = sizeCalculator;
+            FixedSize = 0;
+            Tag = tag;
+            DefaultValue = defaultValue;
+            tagSize = CodedOutputStream.ComputeRawVarint32Size(tag);
+            // Detect packed-ness once, so we can check for it within RepeatedField<T>.
+            PackedRepeatedField = IsPackedRepeatedField(tag);
+        }
+
+        /// <summary>
+        /// Write a tag and the given value, *if* the value is not the default.
+        /// </summary>
+        public void WriteTagAndValue(CodedOutputStream output, T value)
+        {
+            if (!IsDefault(value))
+            {
+                output.WriteTag(Tag);
+                ValueWriter(output, value);
+            }
+        }
+
+        /// <summary>
+        /// Reads a value of the codec type from the given <see cref="CodedInputStream"/>.
+        /// </summary>
+        /// <param name="input">The input stream to read from.</param>
+        /// <returns>The value read from the stream.</returns>
+        public T Read(CodedInputStream input)
+        {
+            return ValueReader(input);
+        }
+
+        /// <summary>
+        /// Calculates the size required to write the given value, with a tag,
+        /// if the value is not the default.
+        /// </summary>
+        public int CalculateSizeWithTag(T value)
+        {
+            return IsDefault(value) ? 0 : ValueSizeCalculator(value) + tagSize;
+        }
+
+        private bool IsDefault(T value)
+        {
+            return EqualityComparer<T>.Default.Equals(value, DefaultValue);
+        }
+    }
+}

+ 11 - 0
Unity/Assets/ThirdParty/Google.Protobuf/FieldCodec.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: bc2f63c5dd762a74785e957e9e2ff0c9
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 69 - 0
Unity/Assets/ThirdParty/Google.Protobuf/ICustomDiagnosticMessage.cs

@@ -0,0 +1,69 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2016 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// A message type that has a custom string format for diagnostic purposes.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// Calling <see cref="object.ToString"/> on a generated message type normally
+    /// returns the JSON representation. If a message type implements this interface,
+    /// then the <see cref="ToDiagnosticString"/> method will be called instead of the regular
+    /// JSON formatting code, but only when <c>ToString()</c> is called either on the message itself
+    /// or on another message which contains it. This does not affect the normal JSON formatting of
+    /// the message.
+    /// </para>
+    /// <para>
+    /// For example, if you create a proto message representing a GUID, the internal
+    /// representation may be a <c>bytes</c> field or four <c>fixed32</c> fields. However, when debugging
+    /// it may be more convenient to see a result in the same format as <see cref="System.Guid"/> provides.
+    /// </para>
+    /// <para>This interface extends <see cref="IMessage"/> to avoid it accidentally being implemented
+    /// on types other than messages, where it would not be used by anything in the framework.</para>
+    /// </remarks>
+    public interface ICustomDiagnosticMessage : IMessage
+    {
+        /// <summary>
+        /// Returns a string representation of this object, for diagnostic purposes.
+        /// </summary>
+        /// <remarks>
+        /// This method is called when a message is formatted as part of a <see cref="object.ToString"/>
+        /// call. It does not affect the JSON representation used by <see cref="JsonFormatter"/> other than
+        /// in calls to <see cref="JsonFormatter.ToDiagnosticString(IMessage)"/>. While it is recommended
+        /// that the result is valid JSON, this is never assumed by the Protobuf library.
+        /// </remarks>
+        /// <returns>A string representation of this object, for diagnostic purposes.</returns>
+        string ToDiagnosticString();
+    }
+}

+ 11 - 0
Unity/Assets/ThirdParty/Google.Protobuf/ICustomDiagnosticMessage.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4e3f9f48b78790d40b93778ba6fc08aa
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 64 - 0
Unity/Assets/ThirdParty/Google.Protobuf/IMessage.cs

@@ -0,0 +1,64 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Interface for a Protocol Buffers message, supporting
+    /// basic operations required for serialization.
+    /// </summary>
+    public interface IMessage
+    {
+        /// <summary>
+        /// Merges the data from the specified coded input stream with the current message.
+        /// </summary>
+        /// <remarks>See the user guide for precise merge semantics.</remarks>
+        /// <param name="input"></param>
+        void MergeFrom(CodedInputStream input);
+
+        /// <summary>
+        /// Writes the data to the given coded output stream.
+        /// </summary>
+        /// <param name="output">Coded output stream to write the data to. Must not be null.</param>
+        void WriteTo(CodedOutputStream output);
+
+        /// <summary>
+        /// Calculates the size of this message in Protocol Buffer wire format, in bytes.
+        /// </summary>
+        /// <returns>The number of bytes required to write this message
+        /// to a coded output stream.</returns>
+        int CalculateSize();
+
+    }
+
+}

+ 11 - 0
Unity/Assets/ThirdParty/Google.Protobuf/IMessage.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 99b4394158577934492f893a057dc06f
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 129 - 0
Unity/Assets/ThirdParty/Google.Protobuf/InvalidProtocolBufferException.cs

@@ -0,0 +1,129 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.IO;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Thrown when a protocol message being parsed is invalid in some way,
+    /// e.g. it contains a malformed varint or a negative byte length.
+    /// </summary>
+    public sealed class InvalidProtocolBufferException : IOException
+    {
+        internal InvalidProtocolBufferException(string message)
+            : base(message)
+        {
+        }
+
+        internal InvalidProtocolBufferException(string message, Exception innerException)
+            : base(message, innerException)
+        {
+        }
+
+        internal static InvalidProtocolBufferException MoreDataAvailable()
+        {
+            return new InvalidProtocolBufferException(
+                "Completed reading a message while more data was available in the stream.");
+        }
+
+        internal static InvalidProtocolBufferException TruncatedMessage()
+        {
+            return new InvalidProtocolBufferException(
+                "While parsing a protocol message, the input ended unexpectedly " +
+                "in the middle of a field.  This could mean either that the " +
+                "input has been truncated or that an embedded message " +
+                "misreported its own length.");
+        }
+
+        internal static InvalidProtocolBufferException NegativeSize()
+        {
+            return new InvalidProtocolBufferException(
+                "CodedInputStream encountered an embedded string or message " +
+                "which claimed to have negative size.");
+        }
+
+        internal static InvalidProtocolBufferException MalformedVarint()
+        {
+            return new InvalidProtocolBufferException(
+                "CodedInputStream encountered a malformed varint.");
+        }
+
+        /// <summary>
+        /// Creates an exception for an error condition of an invalid tag being encountered.
+        /// </summary>
+        internal static InvalidProtocolBufferException InvalidTag()
+        {
+            return new InvalidProtocolBufferException(
+                "Protocol message contained an invalid tag (zero).");
+        }
+
+        internal static InvalidProtocolBufferException InvalidBase64(Exception innerException)
+        {
+            return new InvalidProtocolBufferException("Invalid base64 data", innerException);
+        }
+
+        internal static InvalidProtocolBufferException InvalidEndTag()
+        {
+            return new InvalidProtocolBufferException(
+                "Protocol message end-group tag did not match expected tag.");
+        }
+
+        internal static InvalidProtocolBufferException RecursionLimitExceeded()
+        {
+            return new InvalidProtocolBufferException(
+                "Protocol message had too many levels of nesting.  May be malicious.  " +
+                "Use CodedInputStream.SetRecursionLimit() to increase the depth limit.");
+        }
+
+        internal static InvalidProtocolBufferException JsonRecursionLimitExceeded()
+        {
+            return new InvalidProtocolBufferException(
+                "Protocol message had too many levels of nesting.  May be malicious.  " +
+                "Use JsonParser.Settings to increase the depth limit.");
+        }
+
+        internal static InvalidProtocolBufferException SizeLimitExceeded()
+        {
+            return new InvalidProtocolBufferException(
+                "Protocol message was too large.  May be malicious.  " +
+                "Use CodedInputStream.SetSizeLimit() to increase the size limit.");
+        }
+
+        internal static InvalidProtocolBufferException InvalidMessageStreamTag()
+        {
+            return new InvalidProtocolBufferException(
+                "Stream of protocol messages had invalid tag. Expected tag is length-delimited field 1.");
+        }
+    }
+}

+ 11 - 0
Unity/Assets/ThirdParty/Google.Protobuf/InvalidProtocolBufferException.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 3eb2be644ccc6fc4187e38443cc47ea5
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 110 - 0
Unity/Assets/ThirdParty/Google.Protobuf/LimitedInputStream.cs

@@ -0,0 +1,110 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+    
+using System;
+using System.IO;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Stream implementation which proxies another stream, only allowing a certain amount
+    /// of data to be read. Note that this is only used to read delimited streams, so it
+    /// doesn't attempt to implement everything.
+    /// </summary>
+    internal sealed class LimitedInputStream : Stream
+    {
+        private readonly Stream proxied;
+        private int bytesLeft;
+
+        internal LimitedInputStream(Stream proxied, int size)
+        {
+            this.proxied = proxied;
+            bytesLeft = size;
+        }
+
+        public override bool CanRead
+        {
+            get { return true; }
+        }
+
+        public override bool CanSeek
+        {
+            get { return false; }
+        }
+
+        public override bool CanWrite
+        {
+            get { return false; }
+        }
+
+        public override void Flush()
+        {
+        }
+
+        public override long Length
+        {
+            get { throw new NotSupportedException(); }
+        }
+
+        public override long Position
+        {
+            get { throw new NotSupportedException(); }
+            set { throw new NotSupportedException(); }
+        }
+
+        public override int Read(byte[] buffer, int offset, int count)
+        {
+            if (bytesLeft > 0)
+            {
+                int bytesRead = proxied.Read(buffer, offset, Math.Min(bytesLeft, count));
+                bytesLeft -= bytesRead;
+                return bytesRead;
+            }
+            return 0;
+        }
+
+        public override long Seek(long offset, SeekOrigin origin)
+        {
+            throw new NotSupportedException();
+        }
+
+        public override void SetLength(long value)
+        {
+            throw new NotSupportedException();
+        }
+
+        public override void Write(byte[] buffer, int offset, int count)
+        {
+            throw new NotSupportedException();
+        }
+    }
+}

+ 11 - 0
Unity/Assets/ThirdParty/Google.Protobuf/LimitedInputStream.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f02379e5cbe40714dba4d002f8980dbf
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 171 - 0
Unity/Assets/ThirdParty/Google.Protobuf/MessageExtensions.cs

@@ -0,0 +1,171 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System.IO;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Extension methods on <see cref="IMessage"/> and <see cref="IMessage{T}"/>.
+    /// </summary>
+    public static class MessageExtensions
+    {
+        /// <summary>
+        /// Merges data from the given byte array into an existing message.
+        /// </summary>
+        /// <param name="message">The message to merge the data into.</param>
+        /// <param name="data">The data to merge, which must be protobuf-encoded binary data.</param>
+        public static void MergeFrom(this IMessage message, byte[] data)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(data, "data");
+            CodedInputStream input = new CodedInputStream(data);
+            message.MergeFrom(input);
+            input.CheckReadEndOfStreamTag();
+        }
+        
+        /// <summary>
+        /// Merges data from the given byte array into an existing message.
+        /// </summary>
+        /// <param name="message">The message to merge the data into.</param>
+        /// <param name="data">The data to merge, which must be protobuf-encoded binary data.</param>
+        public static void MergeFrom(this IMessage message, byte[] data, int offset, int length)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(data, "data");
+            CodedInputStream input = new CodedInputStream(data, offset, length);
+            message.MergeFrom(input);
+            input.CheckReadEndOfStreamTag();
+        }
+
+        /// <summary>
+        /// Merges data from the given byte string into an existing message.
+        /// </summary>
+        /// <param name="message">The message to merge the data into.</param>
+        /// <param name="data">The data to merge, which must be protobuf-encoded binary data.</param>
+        public static void MergeFrom(this IMessage message, ByteString data)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(data, "data");
+            CodedInputStream input = data.CreateCodedInput();
+            message.MergeFrom(input);
+            input.CheckReadEndOfStreamTag();
+        }
+
+        /// <summary>
+        /// Merges data from the given stream into an existing message.
+        /// </summary>
+        /// <param name="message">The message to merge the data into.</param>
+        /// <param name="input">Stream containing the data to merge, which must be protobuf-encoded binary data.</param>
+        public static void MergeFrom(this IMessage message, Stream input)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(input, "input");
+            CodedInputStream codedInput = new CodedInputStream(input);
+            message.MergeFrom(codedInput);
+            codedInput.CheckReadEndOfStreamTag();
+        }
+
+        /// <summary>
+        /// Merges length-delimited data from the given stream into an existing message.
+        /// </summary>
+        /// <remarks>
+        /// The stream is expected to contain a length and then the data. Only the amount of data
+        /// specified by the length will be consumed.
+        /// </remarks>
+        /// <param name="message">The message to merge the data into.</param>
+        /// <param name="input">Stream containing the data to merge, which must be protobuf-encoded binary data.</param>
+        public static void MergeDelimitedFrom(this IMessage message, Stream input)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(input, "input");
+            int size = (int) CodedInputStream.ReadRawVarint32(input);
+            Stream limitedStream = new LimitedInputStream(input, size);
+            message.MergeFrom(limitedStream);
+        }
+
+        /// <summary>
+        /// Converts the given message into a byte array in protobuf encoding.
+        /// </summary>
+        /// <param name="message">The message to convert.</param>
+        /// <returns>The message data as a byte array.</returns>
+        public static byte[] ToByteArray(this IMessage message)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            byte[] result = new byte[message.CalculateSize()];
+            CodedOutputStream output = new CodedOutputStream(result);
+            message.WriteTo(output);
+            output.CheckNoSpaceLeft();
+            return result;
+        }
+
+        /// <summary>
+        /// Writes the given message data to the given stream in protobuf encoding.
+        /// </summary>
+        /// <param name="message">The message to write to the stream.</param>
+        /// <param name="output">The stream to write to.</param>
+        public static void WriteTo(this IMessage message, Stream output)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(output, "output");
+            CodedOutputStream codedOutput = new CodedOutputStream(output);
+            message.WriteTo(codedOutput);
+            codedOutput.Flush();
+        }
+
+        /// <summary>
+        /// Writes the length and then data of the given message to a stream.
+        /// </summary>
+        /// <param name="message">The message to write.</param>
+        /// <param name="output">The output stream to write to.</param>
+        public static void WriteDelimitedTo(this IMessage message, Stream output)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(output, "output");
+            CodedOutputStream codedOutput = new CodedOutputStream(output);
+            codedOutput.WriteRawVarint32((uint)message.CalculateSize());
+            message.WriteTo(codedOutput);
+            codedOutput.Flush();
+        }
+
+        /// <summary>
+        /// Converts the given message into a byte string in protobuf encoding.
+        /// </summary>
+        /// <param name="message">The message to convert.</param>
+        /// <returns>The message data as a byte string.</returns>
+        public static ByteString ToByteString(this IMessage message)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            return ByteString.AttachBytes(message.ToByteArray());
+        }        
+    }
+}

+ 11 - 0
Unity/Assets/ThirdParty/Google.Protobuf/MessageExtensions.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 23cd5cb094c72654abdb3a2a71ee5a80
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 241 - 0
Unity/Assets/ThirdParty/Google.Protobuf/MessageParser.cs

@@ -0,0 +1,241 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+    
+using System;
+using System.IO;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// A general message parser, typically used by reflection-based code as all the methods
+    /// return simple <see cref="IMessage"/>.
+    /// </summary>
+    public class MessageParser
+    {
+        private Func<IMessage> factory;
+
+        internal MessageParser(Func<IMessage> factory)
+        {
+            this.factory = factory;
+        }
+
+        /// <summary>
+        /// Creates a template instance ready for population.
+        /// </summary>
+        /// <returns>An empty message.</returns>
+        internal IMessage CreateTemplate()
+        {
+            return factory();
+        }
+
+        /// <summary>
+        /// Parses a message from a byte array.
+        /// </summary>
+        /// <param name="data">The byte array containing the message. Must not be null.</param>
+        /// <returns>The newly parsed message.</returns>
+        public IMessage ParseFrom(byte[] data)
+        {
+            ProtoPreconditions.CheckNotNull(data, "data");
+            IMessage message = factory();
+            message.MergeFrom(data);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a message from the given byte string.
+        /// </summary>
+        /// <param name="data">The data to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public IMessage ParseFrom(ByteString data)
+        {
+            ProtoPreconditions.CheckNotNull(data, "data");
+            IMessage message = factory();
+            message.MergeFrom(data);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a message from the given stream.
+        /// </summary>
+        /// <param name="input">The stream to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public IMessage ParseFrom(Stream input)
+        {
+            IMessage message = factory();
+            message.MergeFrom(input);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a length-delimited message from the given stream.
+        /// </summary>
+        /// <remarks>
+        /// The stream is expected to contain a length and then the data. Only the amount of data
+        /// specified by the length will be consumed.
+        /// </remarks>
+        /// <param name="input">The stream to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public IMessage ParseDelimitedFrom(Stream input)
+        {
+            IMessage message = factory();
+            message.MergeDelimitedFrom(input);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a message from the given coded input stream.
+        /// </summary>
+        /// <param name="input">The stream to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public IMessage ParseFrom(CodedInputStream input)
+        {
+            IMessage message = factory();
+            message.MergeFrom(input);
+            return message;
+        }
+
+    }
+
+    /// <summary>
+    /// A parser for a specific message type.
+    /// </summary>
+    /// <remarks>
+    /// <p>
+    /// This delegates most behavior to the
+    /// <see cref="IMessage.MergeFrom"/> implementation within the original type, but
+    /// provides convenient overloads to parse from a variety of sources.
+    /// </p>
+    /// <p>
+    /// Most applications will never need to create their own instances of this type;
+    /// instead, use the static <c>Parser</c> property of a generated message type to obtain a
+    /// parser for that type.
+    /// </p>
+    /// </remarks>
+    /// <typeparam name="T">The type of message to be parsed.</typeparam>
+    public sealed class MessageParser<T> : MessageParser where T : IMessage
+    {
+        // Implementation note: all the methods here *could* just delegate up to the base class and cast the result.
+        // The current implementation avoids a virtual method call and a cast, which *may* be significant in some cases.
+        // Benchmarking work is required to measure the significance - but it's only a few lines of code in any case.
+        // The API wouldn't change anyway - just the implementation - so this work can be deferred.
+        private readonly Func<T> factory; 
+
+        /// <summary>
+        /// Creates a new parser.
+        /// </summary>
+        /// <remarks>
+        /// The factory method is effectively an optimization over using a generic constraint
+        /// to require a parameterless constructor: delegates are significantly faster to execute.
+        /// </remarks>
+        /// <param name="factory">Function to invoke when a new, empty message is required.</param>
+        public MessageParser(Func<T> factory) : base(() => factory())
+        {
+            this.factory = factory;
+        }
+
+        /// <summary>
+        /// Creates a template instance ready for population.
+        /// </summary>
+        /// <returns>An empty message.</returns>
+        internal new T CreateTemplate()
+        {
+            return factory();
+        }
+
+        /// <summary>
+        /// Parses a message from a byte array.
+        /// </summary>
+        /// <param name="data">The byte array containing the message. Must not be null.</param>
+        /// <returns>The newly parsed message.</returns>
+        public new T ParseFrom(byte[] data)
+        {
+            ProtoPreconditions.CheckNotNull(data, "data");
+            T message = factory();
+            message.MergeFrom(data);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a message from the given byte string.
+        /// </summary>
+        /// <param name="data">The data to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public new T ParseFrom(ByteString data)
+        {
+            ProtoPreconditions.CheckNotNull(data, "data");
+            T message = factory();
+            message.MergeFrom(data);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a message from the given stream.
+        /// </summary>
+        /// <param name="input">The stream to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public new T ParseFrom(Stream input)
+        {
+            T message = factory();
+            message.MergeFrom(input);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a length-delimited message from the given stream.
+        /// </summary>
+        /// <remarks>
+        /// The stream is expected to contain a length and then the data. Only the amount of data
+        /// specified by the length will be consumed.
+        /// </remarks>
+        /// <param name="input">The stream to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public new T ParseDelimitedFrom(Stream input)
+        {
+            T message = factory();
+            message.MergeDelimitedFrom(input);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a message from the given coded input stream.
+        /// </summary>
+        /// <param name="input">The stream to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public new T ParseFrom(CodedInputStream input)
+        {
+            T message = factory();
+            message.MergeFrom(input);
+            return message;
+        }
+
+    }
+}

+ 11 - 0
Unity/Assets/ThirdParty/Google.Protobuf/MessageParser.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 1c7045bb59482bd4ba45e875f377820b
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 79 - 0
Unity/Assets/ThirdParty/Google.Protobuf/ProtoPreconditions.cs

@@ -0,0 +1,79 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Helper methods for throwing exceptions when preconditions are not met.
+    /// </summary>
+    /// <remarks>
+    /// This class is used internally and by generated code; it is not particularly
+    /// expected to be used from application code, although nothing prevents it
+    /// from being used that way.
+    /// </remarks>
+    public static class ProtoPreconditions
+    {
+        /// <summary>
+        /// Throws an ArgumentNullException if the given value is null, otherwise
+        /// return the value to the caller.
+        /// </summary>
+        public static T CheckNotNull<T>(T value, string name) where T : class
+        {
+            if (value == null)
+            {
+                throw new ArgumentNullException(name);
+            }
+            return value;
+        }
+
+        /// <summary>
+        /// Throws an ArgumentNullException if the given value is null, otherwise
+        /// return the value to the caller.
+        /// </summary>
+        /// <remarks>
+        /// This is equivalent to <see cref="CheckNotNull{T}(T, string)"/> but without the type parameter
+        /// constraint. In most cases, the constraint is useful to prevent you from calling CheckNotNull
+        /// with a value type - but it gets in the way if either you want to use it with a nullable
+        /// value type, or you want to use it with an unconstrained type parameter.
+        /// </remarks>
+        internal static T CheckNotNullUnconstrained<T>(T value, string name)
+        {
+            if (value == null)
+            {
+                throw new ArgumentNullException(name);
+            }
+            return value;
+        }
+    }
+}

+ 11 - 0
Unity/Assets/ThirdParty/Google.Protobuf/ProtoPreconditions.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ec2d66cb17ca74d49890f00206696580
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 104 - 0
Unity/Assets/ThirdParty/Google.Protobuf/WireFormat.cs

@@ -0,0 +1,104 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// This class is used internally by the Protocol Buffer Library and generated
+    /// message implementations. It is public only for the sake of those generated
+    /// messages. Others should not use this class directly.
+    /// <para>
+    /// This class contains constants and helper functions useful for dealing with
+    /// the Protocol Buffer wire format.
+    /// </para>
+    /// </summary>
+    public static class WireFormat
+    {
+        /// <summary>
+        /// Wire types within protobuf encoding.
+        /// </summary>
+        public enum WireType : uint
+        {
+            /// <summary>
+            /// Variable-length integer.
+            /// </summary>
+            Varint = 0,
+            /// <summary>
+            /// A fixed-length 64-bit value.
+            /// </summary>
+            Fixed64 = 1,
+            /// <summary>
+            /// A length-delimited value, i.e. a length followed by that many bytes of data.
+            /// </summary>
+            LengthDelimited = 2,
+            /// <summary>
+            /// A "start group" value - not supported by this implementation.
+            /// </summary>
+            StartGroup = 3,
+            /// <summary>
+            /// An "end group" value - not supported by this implementation.
+            /// </summary>
+            EndGroup = 4,
+            /// <summary>
+            /// A fixed-length 32-bit value.
+            /// </summary>
+            Fixed32 = 5
+        }
+        
+        private const int TagTypeBits = 3;
+        private const uint TagTypeMask = (1 << TagTypeBits) - 1;
+
+        /// <summary>
+        /// Given a tag value, determines the wire type (lower 3 bits).
+        /// </summary>
+        public static WireType GetTagWireType(uint tag)
+        {
+            return (WireType) (tag & TagTypeMask);
+        }
+
+        /// <summary>
+        /// Given a tag value, determines the field number (the upper 29 bits).
+        /// </summary>
+        public static int GetTagFieldNumber(uint tag)
+        {
+            return (int) tag >> TagTypeBits;
+        }
+
+        /// <summary>
+        /// Makes a tag value given a field number and wire type.
+        /// </summary>
+        public static uint MakeTag(int fieldNumber, WireType wireType)
+        {
+            return (uint) (fieldNumber << TagTypeBits) | (uint) wireType;
+        }        
+    }
+}

+ 11 - 0
Unity/Assets/ThirdParty/Google.Protobuf/WireFormat.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 7bf59a3ce666cd14392ea36d61668d87
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 0 - 4
Unity/Assets/ThirdParty/ILRuntime/Generated/CLRBindings.cs

@@ -34,7 +34,6 @@ namespace ILRuntime.Runtime.Generated
             ETModel_Game_Binding.Register(app);
             ETModel_Entity_Binding.Register(app);
             ETModel_ResourcesComponent_Binding.Register(app);
-            ETModel_Actor_CreateUnits_Binding.Register(app);
             System_Collections_Generic_List_1_UnitInfo_Binding.Register(app);
             System_Collections_Generic_List_1_UnitInfo_Binding_Enumerator_Binding.Register(app);
             ETModel_UnitInfo_Binding.Register(app);
@@ -80,7 +79,6 @@ namespace ILRuntime.Runtime.Generated
             ETModel_Component_Binding.Register(app);
             ETModel_Packet_Binding.Register(app);
             ETModel_NetworkComponent_Binding.Register(app);
-            ETModel_IMessagePacker_Binding.Register(app);
             ETModel_MessageInfo_Binding.Register(app);
             ETModel_ProtobufHelper_Binding.Register(app);
             System_Threading_Tasks_TaskCompletionSource_1_ILTypeInstance_Binding.Register(app);
@@ -93,7 +91,6 @@ namespace ILRuntime.Runtime.Generated
             ETModel_MessageDispatherComponent_Binding.Register(app);
             ETModel_MessageAttribute_Binding.Register(app);
             ETModel_DoubleMap_2_UInt16_Type_Binding.Register(app);
-            ProtoBuf_PType_Binding.Register(app);
             System_Collections_Generic_Dictionary_2_String_ILTypeInstance_Binding.Register(app);
             UnityEngine_GameObject_Binding.Register(app);
             ETModel_UIFactoryAttribute_Binding.Register(app);
@@ -108,7 +105,6 @@ namespace ILRuntime.Runtime.Generated
             ReferenceCollector_Binding.Register(app);
             UnityEngine_UI_Button_Binding.Register(app);
             ETModel_ActionHelper_Binding.Register(app);
-            ETModel_Actor_TestRequest_Binding.Register(app);
             System_Threading_Tasks_Task_1_IResponse_Binding.Register(app);
             System_Runtime_CompilerServices_TaskAwaiter_1_IResponse_Binding.Register(app);
             ETModel_Actor_TransferRequest_Binding.Register(app);

Некоторые файлы не были показаны из-за большого количества измененных файлов