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

1.服务端消息放到Model层
2.消除protobuf消息内部包含class类型跟repeated class类型的GC,使用了MessagePool来创建跟回收消息

tanghai 7 лет назад
Родитель
Сommit
0787328747

+ 2 - 1
Proto/HotfixMessage.proto

@@ -66,5 +66,6 @@ message G2C_PlayerInfo // IResponse
 	int32 RpcId = 90;
 	int32 Error = 91;
 	string Message = 92;
-	PlayerInfo PlayerInfos = 1;
+	PlayerInfo PlayerInfo = 1;
+	repeated PlayerInfo PlayerInfos = 2;
 }

+ 20 - 0
Server/Hotfix/Handler/G2C_PlayerInfoHandler.cs

@@ -0,0 +1,20 @@
+using System;
+using ETModel;
+
+namespace ETHotfix
+{
+	// 用来测试消息包含复杂类型,是否产生gc
+	[MessageHandler(AppType.Gate)]
+	public class C2G_PlayerInfoHandler : AMRpcHandler<C2G_PlayerInfo, G2C_PlayerInfo>
+	{
+		protected override void Run(Session session, C2G_PlayerInfo message, Action<G2C_PlayerInfo> reply)
+		{
+			G2C_PlayerInfo g2CPlayerInfo = new G2C_PlayerInfo();
+			g2CPlayerInfo.PlayerInfo = new PlayerInfo();
+			g2CPlayerInfo.PlayerInfos.Add(new PlayerInfo());
+			g2CPlayerInfo.PlayerInfos.Add(new PlayerInfo());
+			g2CPlayerInfo.PlayerInfos.Add(new PlayerInfo());
+			reply(g2CPlayerInfo);
+		}
+	}
+}

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

@@ -20,12 +20,6 @@
     <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 - 1
Server/Hotfix/Module/Message/InnerMessage.cs → Server/Model/Module/Message/InnerMessage.cs

@@ -1,6 +1,6 @@
 using ETModel;
 using System.Collections.Generic;
-namespace ETHotfix
+namespace ETModel
 {
 /// <summary>
 /// 传送unit

+ 1 - 1
Server/Hotfix/Module/Message/InnerOpcode.cs → Server/Model/Module/Message/InnerOpcode.cs

@@ -1,4 +1,4 @@
-namespace ETHotfix
+namespace ETModel
 {
 	public static partial class InnerOpcode
 	{

+ 7 - 0
Server/Model/Server.Model.csproj

@@ -88,6 +88,7 @@
     <Compile Include="..\..\Unity\Assets\Scripts\Module\Message\MessageAttribute.cs" Link="Module\Message\MessageAttribute.cs" />
     <Compile Include="..\..\Unity\Assets\Scripts\Module\Message\MessageHandlerAttribute.cs" Link="Module\Message\MessageHandlerAttribute.cs" />
     <Compile Include="..\..\Unity\Assets\Scripts\Module\Message\MessageInfo.cs" Link="Module\Message\MessageInfo.cs" />
+    <Compile Include="..\..\Unity\Assets\Scripts\Module\Message\MessagePool.cs" Link="Module\Message\MessagePool.cs" />
     <Compile Include="..\..\Unity\Assets\Scripts\Module\Message\NetworkComponent.cs" Link="Module\Message\NetworkComponent.cs" />
     <Compile Include="..\..\Unity\Assets\Scripts\Module\Message\Network\AChannel.cs" Link="Module\Message\Network\AChannel.cs" />
     <Compile Include="..\..\Unity\Assets\Scripts\Module\Message\Network\AService.cs" Link="Module\Message\Network\AService.cs" />
@@ -101,6 +102,8 @@
     <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\OuterMessage.cs" Link="Module\Message\OuterMessage.cs" />
+    <Compile Include="..\..\Unity\Assets\Scripts\Module\Message\OuterOpcode.cs" Link="Module\Message\OuterOpcode.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" />
@@ -112,6 +115,9 @@
     <Compile Include="..\..\Unity\Assets\Scripts\Module\Numeric\NumericWatcherAttribute.cs" Link="Module\Numeric\NumericWatcherAttribute.cs" />
     <Compile Include="..\..\Unity\Assets\Scripts\Module\Numeric\NumericWatcherComponent.cs" Link="Module\Numeric\NumericWatcherComponent.cs" />
     <Compile Include="..\..\Unity\Assets\Scripts\Other\AppType.cs" Link="Other\AppType.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" />
+    <Compile Include="..\..\Unity\Hotfix\Module\Message\MessagePool.cs" Link="Module\Message\MessagePool\MessagePool.cs" />
   </ItemGroup>
   <ItemGroup>
     <PackageReference Include="CommandLineParser" Version="2.2.1" />
@@ -131,6 +137,7 @@
     <Folder Include="Component\Config\" />
     <Folder Include="Module\Message\Network\KCP\" />
     <Folder Include="Module\Message\Network\TCP\" />
+    <Folder Include="Module\Message\MessagePool\" />
     <Folder Include="Module\Numeric\" />
   </ItemGroup>
 </Project>

+ 3 - 3
Unity/Assets/Editor/Proto2CsEditor/InnerProto2CS.cs

@@ -18,7 +18,7 @@ namespace ETEditor
 	public static class InnerProto2CS
 	{
 		private const string protoPath = "../Proto/";
-		private const string serverMessagePath = "../Server/Hotfix/Module/Message/";
+		private const string serverMessagePath = "../Server/Model/Module/Message/";
 		private static readonly char[] splitChars = { ' ', '\t' };
 		private static readonly List<OpcodeInfo> msgOpcode = new List<OpcodeInfo>();
 		
@@ -26,8 +26,8 @@ namespace ETEditor
 		public static void Proto2CS()
 		{
 			msgOpcode.Clear();
-			Proto2CS("ETHotfix", "InnerMessage.proto", serverMessagePath, "InnerOpcode", 1000);
-			GenerateOpcode("ETHotfix", "InnerOpcode", serverMessagePath);
+			Proto2CS("ETModel", "InnerMessage.proto", serverMessagePath, "InnerOpcode", 1000);
+			GenerateOpcode("ETModel", "InnerOpcode", serverMessagePath);
 
 			AssetDatabase.Refresh();
 		}

+ 118 - 0
Unity/Assets/Scripts/Helper/Dumper.cs

@@ -0,0 +1,118 @@
+using System;
+using System.Collections;
+using System.Reflection;
+using System.Text;
+using Google.Protobuf;
+using UnityEngine;
+
+namespace ETModel
+{
+    public static class Dumper
+    {
+        private static readonly StringBuilder _text = new StringBuilder("", 1024);
+
+        private static void AppendIndent(int num)
+        {
+            _text.Append(' ', num);
+        }
+
+        private static void DoDump(object obj)
+        {
+            if (obj == null)
+            {
+                _text.Append("null");
+                _text.Append(",");
+                return;
+            }
+
+            Type t = obj.GetType();
+
+            //repeat field
+            if (obj is IList)
+            {
+                /*
+                _text.Append(t.FullName);
+                _text.Append(",");
+                AppendIndent(1);
+                */
+
+                _text.Append("[");
+                IList list = obj as IList;
+                foreach (object v in list)
+                {
+                    DoDump(v);
+                }
+
+                _text.Append("]");
+            }
+            else if (t.IsValueType)
+            {
+                _text.Append(obj);
+                _text.Append(",");
+                AppendIndent(1);
+            }
+            else if (obj is string)
+            {
+                _text.Append("\"");
+                _text.Append(obj);
+                _text.Append("\"");
+                _text.Append(",");
+                AppendIndent(1);
+            }
+            else if (obj is ByteString)
+            {
+                _text.Append("\"");
+                _text.Append(((ByteString) obj).bytes.Utf8ToStr());
+                _text.Append("\"");
+                _text.Append(",");
+                AppendIndent(1);
+            }
+            else if (t.IsArray)
+            {
+                Array a = (Array) obj;
+                _text.Append("[");
+                for (int i = 0; i < a.Length; i++)
+                {
+                    _text.Append(i);
+                    _text.Append(":");
+                    DoDump(a.GetValue(i));
+                }
+
+                _text.Append("]");
+            }
+            else if (t.IsClass)
+            {
+                _text.Append($"<{t.Name}>");
+                _text.Append("{");
+                var fields = t.GetProperties(BindingFlags.Public | BindingFlags.Instance);
+                if (fields.Length > 0)
+                {
+                    foreach (PropertyInfo info in fields)
+                    {
+                        _text.Append(info.Name);
+                        _text.Append(":");
+                        object value = info.GetGetMethod().Invoke(obj, null);
+                        DoDump(value);
+                    }
+                }
+
+                _text.Append("}");
+            }
+            else
+            {
+                Debug.LogWarning("unsupport type: " + t.FullName);
+                _text.Append(obj);
+                _text.Append(",");
+                AppendIndent(1);
+            }
+        }
+
+        public static string DumpAsString(object obj, string hint = "")
+        {
+            _text.Clear();
+            _text.Append(hint);
+            DoDump(obj);
+            return _text.ToString();
+        }
+    }
+}

+ 11 - 0
Unity/Assets/Scripts/Helper/Dumper.cs.meta

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

+ 3 - 2
Unity/Assets/Scripts/Module/FrameSync/FrameMessage.cs

@@ -10,7 +10,7 @@ namespace ETModel {
 
   #region Messages
   public partial class OneFrameMessage : pb::IMessage {
-    private static readonly pb::MessageParser<OneFrameMessage> _parser = new pb::MessageParser<OneFrameMessage>(() => new OneFrameMessage());
+    private static readonly pb::MessageParser<OneFrameMessage> _parser = new pb::MessageParser<OneFrameMessage>(() => (OneFrameMessage)MessagePool.Instance.Fetch(typeof(OneFrameMessage)));
     public static pb::MessageParser<OneFrameMessage> Parser { get { return _parser; } }
 
     private int rpcId_;
@@ -114,7 +114,7 @@ namespace ETModel {
   }
 
   public partial class FrameMessage : pb::IMessage {
-    private static readonly pb::MessageParser<FrameMessage> _parser = new pb::MessageParser<FrameMessage>(() => new FrameMessage());
+    private static readonly pb::MessageParser<FrameMessage> _parser = new pb::MessageParser<FrameMessage>(() => (FrameMessage)MessagePool.Instance.Fetch(typeof(FrameMessage)));
     public static pb::MessageParser<FrameMessage> Parser { get { return _parser; } }
 
     private int rpcId_;
@@ -182,6 +182,7 @@ namespace ETModel {
 
     public void MergeFrom(pb::CodedInputStream input) {
       frame_ = 0;
+      if (typeof(global::ETModel.OneFrameMessage).IsClass) { for (int i = 0; i < message_.Count; i++) { MessagePool.Instance.Recycle(message_[i]); } }
       message_.Clear();
       rpcId_ = 0;
       actorId_ = 0;

+ 50 - 0
Unity/Assets/Scripts/Module/Message/MessagePool.cs

@@ -0,0 +1,50 @@
+using System;
+using System.Collections.Generic;
+
+namespace ETModel
+{
+    public class MessagePool
+    {
+	    public static MessagePool Instance { get; } = new MessagePool();
+	    
+        private readonly Dictionary<Type, Queue<object>> dictionary = new Dictionary<Type, Queue<object>>();
+
+        public object Fetch(Type type)
+        {
+	        Queue<object> queue;
+            if (!this.dictionary.TryGetValue(type, out queue))
+            {
+                queue = new Queue<object>();
+                this.dictionary.Add(type, queue);
+            }
+	        object obj;
+			if (queue.Count > 0)
+            {
+				obj = queue.Dequeue();
+            }
+			else
+			{
+				obj = Activator.CreateInstance(type);	
+			}
+            return obj;
+        }
+
+        public T Fetch<T>() where T: class
+		{
+            T t = (T) this.Fetch(typeof(T));
+			return t;
+		}
+        
+        public void Recycle(object obj)
+        {
+            Type type = obj.GetType();
+	        Queue<object> queue;
+            if (!this.dictionary.TryGetValue(type, out queue))
+            {
+                queue = new Queue<object>();
+				this.dictionary.Add(type, queue);
+            }
+            queue.Enqueue(obj);
+        }
+    }
+}

+ 11 - 0
Unity/Assets/Scripts/Module/Message/MessagePool.cs.meta

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

+ 14 - 36
Unity/Assets/Scripts/Module/Message/OuterMessage.cs

@@ -10,7 +10,7 @@ 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());
+    private static readonly pb::MessageParser<Actor_Test> _parser = new pb::MessageParser<Actor_Test>(() => (Actor_Test)MessagePool.Instance.Fetch(typeof(Actor_Test)));
     public static pb::MessageParser<Actor_Test> Parser { get { return _parser; } }
 
     private int rpcId_;
@@ -95,7 +95,7 @@ namespace ETModel {
   }
 
   public partial class Actor_TestRequest : pb::IMessage {
-    private static readonly pb::MessageParser<Actor_TestRequest> _parser = new pb::MessageParser<Actor_TestRequest>(() => new Actor_TestRequest());
+    private static readonly pb::MessageParser<Actor_TestRequest> _parser = new pb::MessageParser<Actor_TestRequest>(() => (Actor_TestRequest)MessagePool.Instance.Fetch(typeof(Actor_TestRequest)));
     public static pb::MessageParser<Actor_TestRequest> Parser { get { return _parser; } }
 
     private int rpcId_;
@@ -180,7 +180,7 @@ namespace ETModel {
   }
 
   public partial class Actor_TestResponse : pb::IMessage {
-    private static readonly pb::MessageParser<Actor_TestResponse> _parser = new pb::MessageParser<Actor_TestResponse>(() => new Actor_TestResponse());
+    private static readonly pb::MessageParser<Actor_TestResponse> _parser = new pb::MessageParser<Actor_TestResponse>(() => (Actor_TestResponse)MessagePool.Instance.Fetch(typeof(Actor_TestResponse)));
     public static pb::MessageParser<Actor_TestResponse> Parser { get { return _parser; } }
 
     private int rpcId_;
@@ -285,7 +285,7 @@ namespace ETModel {
   }
 
   public partial class Actor_TransferRequest : pb::IMessage {
-    private static readonly pb::MessageParser<Actor_TransferRequest> _parser = new pb::MessageParser<Actor_TransferRequest>(() => new Actor_TransferRequest());
+    private static readonly pb::MessageParser<Actor_TransferRequest> _parser = new pb::MessageParser<Actor_TransferRequest>(() => (Actor_TransferRequest)MessagePool.Instance.Fetch(typeof(Actor_TransferRequest)));
     public static pb::MessageParser<Actor_TransferRequest> Parser { get { return _parser; } }
 
     private int rpcId_;
@@ -370,7 +370,7 @@ namespace ETModel {
   }
 
   public partial class Actor_TransferResponse : pb::IMessage {
-    private static readonly pb::MessageParser<Actor_TransferResponse> _parser = new pb::MessageParser<Actor_TransferResponse>(() => new Actor_TransferResponse());
+    private static readonly pb::MessageParser<Actor_TransferResponse> _parser = new pb::MessageParser<Actor_TransferResponse>(() => (Actor_TransferResponse)MessagePool.Instance.Fetch(typeof(Actor_TransferResponse)));
     public static pb::MessageParser<Actor_TransferResponse> Parser { get { return _parser; } }
 
     private int rpcId_;
@@ -455,7 +455,7 @@ namespace ETModel {
   }
 
   public partial class C2G_EnterMap : pb::IMessage {
-    private static readonly pb::MessageParser<C2G_EnterMap> _parser = new pb::MessageParser<C2G_EnterMap>(() => new C2G_EnterMap());
+    private static readonly pb::MessageParser<C2G_EnterMap> _parser = new pb::MessageParser<C2G_EnterMap>(() => (C2G_EnterMap)MessagePool.Instance.Fetch(typeof(C2G_EnterMap)));
     public static pb::MessageParser<C2G_EnterMap> Parser { get { return _parser; } }
 
     private int rpcId_;
@@ -500,7 +500,7 @@ namespace ETModel {
   }
 
   public partial class G2C_EnterMap : pb::IMessage {
-    private static readonly pb::MessageParser<G2C_EnterMap> _parser = new pb::MessageParser<G2C_EnterMap>(() => new G2C_EnterMap());
+    private static readonly pb::MessageParser<G2C_EnterMap> _parser = new pb::MessageParser<G2C_EnterMap>(() => (G2C_EnterMap)MessagePool.Instance.Fetch(typeof(G2C_EnterMap)));
     public static pb::MessageParser<G2C_EnterMap> Parser { get { return _parser; } }
 
     private int rpcId_;
@@ -625,7 +625,7 @@ namespace ETModel {
   }
 
   public partial class UnitInfo : pb::IMessage {
-    private static readonly pb::MessageParser<UnitInfo> _parser = new pb::MessageParser<UnitInfo>(() => new UnitInfo());
+    private static readonly pb::MessageParser<UnitInfo> _parser = new pb::MessageParser<UnitInfo>(() => (UnitInfo)MessagePool.Instance.Fetch(typeof(UnitInfo)));
     public static pb::MessageParser<UnitInfo> Parser { get { return _parser; } }
 
     private long unitId_;
@@ -710,7 +710,7 @@ namespace ETModel {
   }
 
   public partial class Actor_CreateUnits : pb::IMessage {
-    private static readonly pb::MessageParser<Actor_CreateUnits> _parser = new pb::MessageParser<Actor_CreateUnits>(() => new Actor_CreateUnits());
+    private static readonly pb::MessageParser<Actor_CreateUnits> _parser = new pb::MessageParser<Actor_CreateUnits>(() => (Actor_CreateUnits)MessagePool.Instance.Fetch(typeof(Actor_CreateUnits)));
     public static pb::MessageParser<Actor_CreateUnits> Parser { get { return _parser; } }
 
     private int rpcId_;
@@ -737,20 +737,8 @@ namespace ETModel {
       set { units_ = value; }
     }
 
-    private global::ETModel.UnitInfo aa_;
-    public global::ETModel.UnitInfo Aa {
-      get { return aa_; }
-      set {
-        aa_ = value;
-      }
-    }
-
     public void WriteTo(pb::CodedOutputStream output) {
       units_.WriteTo(output, _repeated_units_codec);
-      if (aa_ != null) {
-        output.WriteRawTag(18);
-        output.WriteMessage(Aa);
-      }
       if (RpcId != 0) {
         output.WriteRawTag(208, 5);
         output.WriteInt32(RpcId);
@@ -770,15 +758,12 @@ namespace ETModel {
         size += 2 + pb::CodedOutputStream.ComputeInt64Size(ActorId);
       }
       size += units_.CalculateSize(_repeated_units_codec);
-      if (aa_ != null) {
-        size += 1 + pb::CodedOutputStream.ComputeMessageSize(Aa);
-      }
       return size;
     }
 
     public void MergeFrom(pb::CodedInputStream input) {
+      if (typeof(global::ETModel.UnitInfo).IsClass) { for (int i = 0; i < units_.Count; i++) { MessagePool.Instance.Recycle(units_[i]); } }
       units_.Clear();
-      aa_ = null;
       rpcId_ = 0;
       actorId_ = 0;
       uint tag;
@@ -791,13 +776,6 @@ namespace ETModel {
             units_.AddEntriesFrom(input, _repeated_units_codec);
             break;
           }
-          case 18: {
-            if (aa_ == null) {
-              aa_ = new global::ETModel.UnitInfo();
-            }
-            input.ReadMessage(aa_);
-            break;
-          }
           case 720: {
             RpcId = input.ReadInt32();
             break;
@@ -813,7 +791,7 @@ namespace ETModel {
   }
 
   public partial class Frame_ClickMap : pb::IMessage {
-    private static readonly pb::MessageParser<Frame_ClickMap> _parser = new pb::MessageParser<Frame_ClickMap>(() => new Frame_ClickMap());
+    private static readonly pb::MessageParser<Frame_ClickMap> _parser = new pb::MessageParser<Frame_ClickMap>(() => (Frame_ClickMap)MessagePool.Instance.Fetch(typeof(Frame_ClickMap)));
     public static pb::MessageParser<Frame_ClickMap> Parser { get { return _parser; } }
 
     private int rpcId_;
@@ -918,7 +896,7 @@ namespace ETModel {
   }
 
   public partial class C2R_Ping : pb::IMessage {
-    private static readonly pb::MessageParser<C2R_Ping> _parser = new pb::MessageParser<C2R_Ping>(() => new C2R_Ping());
+    private static readonly pb::MessageParser<C2R_Ping> _parser = new pb::MessageParser<C2R_Ping>(() => (C2R_Ping)MessagePool.Instance.Fetch(typeof(C2R_Ping)));
     public static pb::MessageParser<C2R_Ping> Parser { get { return _parser; } }
 
     private int rpcId_;
@@ -963,7 +941,7 @@ namespace ETModel {
   }
 
   public partial class R2C_Ping : pb::IMessage {
-    private static readonly pb::MessageParser<R2C_Ping> _parser = new pb::MessageParser<R2C_Ping>(() => new R2C_Ping());
+    private static readonly pb::MessageParser<R2C_Ping> _parser = new pb::MessageParser<R2C_Ping>(() => (R2C_Ping)MessagePool.Instance.Fetch(typeof(R2C_Ping)));
     public static pb::MessageParser<R2C_Ping> Parser { get { return _parser; } }
 
     private int rpcId_;
@@ -1048,7 +1026,7 @@ namespace ETModel {
   }
 
   public partial class G2C_Test : pb::IMessage {
-    private static readonly pb::MessageParser<G2C_Test> _parser = new pb::MessageParser<G2C_Test>(() => new G2C_Test());
+    private static readonly pb::MessageParser<G2C_Test> _parser = new pb::MessageParser<G2C_Test>(() => (G2C_Test)MessagePool.Instance.Fetch(typeof(G2C_Test)));
     public static pb::MessageParser<G2C_Test> Parser { get { return _parser; } }
 
     public void WriteTo(pb::CodedOutputStream output) {

+ 38 - 22
Unity/Hotfix/Module/Message/HotfixMessage.cs

@@ -10,7 +10,7 @@ namespace ETHotfix {
 
   #region Messages
   public partial class C2R_Login : pb::IMessage {
-    private static readonly pb::MessageParser<C2R_Login> _parser = new pb::MessageParser<C2R_Login>(() => new C2R_Login());
+    private static readonly pb::MessageParser<C2R_Login> _parser = new pb::MessageParser<C2R_Login>(() => (C2R_Login)MessagePool.Instance.Fetch(typeof(C2R_Login)));
     public static pb::MessageParser<C2R_Login> Parser { get { return _parser; } }
 
     private int rpcId_;
@@ -101,7 +101,7 @@ namespace ETHotfix {
   }
 
   public partial class R2C_Login : pb::IMessage {
-    private static readonly pb::MessageParser<R2C_Login> _parser = new pb::MessageParser<R2C_Login>(() => new R2C_Login());
+    private static readonly pb::MessageParser<R2C_Login> _parser = new pb::MessageParser<R2C_Login>(() => (R2C_Login)MessagePool.Instance.Fetch(typeof(R2C_Login)));
     public static pb::MessageParser<R2C_Login> Parser { get { return _parser; } }
 
     private int rpcId_;
@@ -226,7 +226,7 @@ namespace ETHotfix {
   }
 
   public partial class C2G_LoginGate : pb::IMessage {
-    private static readonly pb::MessageParser<C2G_LoginGate> _parser = new pb::MessageParser<C2G_LoginGate>(() => new C2G_LoginGate());
+    private static readonly pb::MessageParser<C2G_LoginGate> _parser = new pb::MessageParser<C2G_LoginGate>(() => (C2G_LoginGate)MessagePool.Instance.Fetch(typeof(C2G_LoginGate)));
     public static pb::MessageParser<C2G_LoginGate> Parser { get { return _parser; } }
 
     private int rpcId_;
@@ -294,7 +294,7 @@ namespace ETHotfix {
   }
 
   public partial class G2C_LoginGate : pb::IMessage {
-    private static readonly pb::MessageParser<G2C_LoginGate> _parser = new pb::MessageParser<G2C_LoginGate>(() => new G2C_LoginGate());
+    private static readonly pb::MessageParser<G2C_LoginGate> _parser = new pb::MessageParser<G2C_LoginGate>(() => (G2C_LoginGate)MessagePool.Instance.Fetch(typeof(G2C_LoginGate)));
     public static pb::MessageParser<G2C_LoginGate> Parser { get { return _parser; } }
 
     private int rpcId_;
@@ -399,7 +399,7 @@ namespace ETHotfix {
   }
 
   public partial class G2C_TestHotfixMessage : pb::IMessage {
-    private static readonly pb::MessageParser<G2C_TestHotfixMessage> _parser = new pb::MessageParser<G2C_TestHotfixMessage>(() => new G2C_TestHotfixMessage());
+    private static readonly pb::MessageParser<G2C_TestHotfixMessage> _parser = new pb::MessageParser<G2C_TestHotfixMessage>(() => (G2C_TestHotfixMessage)MessagePool.Instance.Fetch(typeof(G2C_TestHotfixMessage)));
     public static pb::MessageParser<G2C_TestHotfixMessage> Parser { get { return _parser; } }
 
     private string info_ = "";
@@ -444,7 +444,7 @@ namespace ETHotfix {
   }
 
   public partial class C2M_TestActorRequest : pb::IMessage {
-    private static readonly pb::MessageParser<C2M_TestActorRequest> _parser = new pb::MessageParser<C2M_TestActorRequest>(() => new C2M_TestActorRequest());
+    private static readonly pb::MessageParser<C2M_TestActorRequest> _parser = new pb::MessageParser<C2M_TestActorRequest>(() => (C2M_TestActorRequest)MessagePool.Instance.Fetch(typeof(C2M_TestActorRequest)));
     public static pb::MessageParser<C2M_TestActorRequest> Parser { get { return _parser; } }
 
     private int rpcId_;
@@ -529,7 +529,7 @@ namespace ETHotfix {
   }
 
   public partial class M2C_TestActorResponse : pb::IMessage {
-    private static readonly pb::MessageParser<M2C_TestActorResponse> _parser = new pb::MessageParser<M2C_TestActorResponse>(() => new M2C_TestActorResponse());
+    private static readonly pb::MessageParser<M2C_TestActorResponse> _parser = new pb::MessageParser<M2C_TestActorResponse>(() => (M2C_TestActorResponse)MessagePool.Instance.Fetch(typeof(M2C_TestActorResponse)));
     public static pb::MessageParser<M2C_TestActorResponse> Parser { get { return _parser; } }
 
     private int rpcId_;
@@ -634,7 +634,7 @@ namespace ETHotfix {
   }
 
   public partial class PlayerInfo : pb::IMessage {
-    private static readonly pb::MessageParser<PlayerInfo> _parser = new pb::MessageParser<PlayerInfo>(() => new PlayerInfo());
+    private static readonly pb::MessageParser<PlayerInfo> _parser = new pb::MessageParser<PlayerInfo>(() => (PlayerInfo)MessagePool.Instance.Fetch(typeof(PlayerInfo)));
     public static pb::MessageParser<PlayerInfo> Parser { get { return _parser; } }
 
     private int rpcId_;
@@ -679,7 +679,7 @@ namespace ETHotfix {
   }
 
   public partial class C2G_PlayerInfo : pb::IMessage {
-    private static readonly pb::MessageParser<C2G_PlayerInfo> _parser = new pb::MessageParser<C2G_PlayerInfo>(() => new C2G_PlayerInfo());
+    private static readonly pb::MessageParser<C2G_PlayerInfo> _parser = new pb::MessageParser<C2G_PlayerInfo>(() => (C2G_PlayerInfo)MessagePool.Instance.Fetch(typeof(C2G_PlayerInfo)));
     public static pb::MessageParser<C2G_PlayerInfo> Parser { get { return _parser; } }
 
     private int rpcId_;
@@ -724,7 +724,7 @@ namespace ETHotfix {
   }
 
   public partial class G2C_PlayerInfo : pb::IMessage {
-    private static readonly pb::MessageParser<G2C_PlayerInfo> _parser = new pb::MessageParser<G2C_PlayerInfo>(() => new G2C_PlayerInfo());
+    private static readonly pb::MessageParser<G2C_PlayerInfo> _parser = new pb::MessageParser<G2C_PlayerInfo>(() => (G2C_PlayerInfo)MessagePool.Instance.Fetch(typeof(G2C_PlayerInfo)));
     public static pb::MessageParser<G2C_PlayerInfo> Parser { get { return _parser; } }
 
     private int rpcId_;
@@ -751,19 +751,28 @@ namespace ETHotfix {
       }
     }
 
-    private global::ETHotfix.PlayerInfo playerInfos_;
-    public global::ETHotfix.PlayerInfo PlayerInfos {
-      get { return playerInfos_; }
+    private global::ETHotfix.PlayerInfo playerInfo_;
+    public global::ETHotfix.PlayerInfo PlayerInfo {
+      get { return playerInfo_; }
       set {
-        playerInfos_ = value;
+        playerInfo_ = value;
       }
     }
 
+    private static readonly pb::FieldCodec<global::ETHotfix.PlayerInfo> _repeated_playerInfos_codec
+        = pb::FieldCodec.ForMessage(18, global::ETHotfix.PlayerInfo.Parser);
+    private pbc::RepeatedField<global::ETHotfix.PlayerInfo> playerInfos_ = new pbc::RepeatedField<global::ETHotfix.PlayerInfo>();
+    public pbc::RepeatedField<global::ETHotfix.PlayerInfo> PlayerInfos {
+      get { return playerInfos_; }
+      set { playerInfos_ = value; }
+    }
+
     public void WriteTo(pb::CodedOutputStream output) {
-      if (playerInfos_ != null) {
+      if (playerInfo_ != null) {
         output.WriteRawTag(10);
-        output.WriteMessage(PlayerInfos);
+        output.WriteMessage(PlayerInfo);
       }
+      playerInfos_.WriteTo(output, _repeated_playerInfos_codec);
       if (RpcId != 0) {
         output.WriteRawTag(208, 5);
         output.WriteInt32(RpcId);
@@ -789,14 +798,17 @@ namespace ETHotfix {
       if (Message.Length != 0) {
         size += 2 + pb::CodedOutputStream.ComputeStringSize(Message);
       }
-      if (playerInfos_ != null) {
-        size += 1 + pb::CodedOutputStream.ComputeMessageSize(PlayerInfos);
+      if (playerInfo_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(PlayerInfo);
       }
+      size += playerInfos_.CalculateSize(_repeated_playerInfos_codec);
       return size;
     }
 
     public void MergeFrom(pb::CodedInputStream input) {
-      playerInfos_ = null;
+      if (playerInfo_ != null) MessagePool.Instance.Recycle(playerInfo_); playerInfo_ = null;
+      if (typeof(global::ETHotfix.PlayerInfo).IsClass) { for (int i = 0; i < playerInfos_.Count; i++) { MessagePool.Instance.Recycle(playerInfos_[i]); } }
+      playerInfos_.Clear();
       rpcId_ = 0;
       error_ = 0;
       message_ = "";
@@ -807,10 +819,14 @@ namespace ETHotfix {
             input.SkipLastField();
             break;
           case 10: {
-            if (playerInfos_ == null) {
-              playerInfos_ = new global::ETHotfix.PlayerInfo();
+            if (playerInfo_ == null) {
+              playerInfo_ = new global::ETHotfix.PlayerInfo();
             }
-            input.ReadMessage(playerInfos_);
+            input.ReadMessage(playerInfo_);
+            break;
+          }
+          case 18: {
+            playerInfos_.AddEntriesFrom(input, _repeated_playerInfos_codec);
             break;
           }
           case 720: {

+ 50 - 0
Unity/Hotfix/Module/Message/MessagePool.cs

@@ -0,0 +1,50 @@
+using System;
+using System.Collections.Generic;
+
+namespace ETHotfix
+{
+    public class MessagePool
+    {
+	    public static MessagePool Instance { get; } = new MessagePool();
+	    
+        private readonly Dictionary<Type, Queue<object>> dictionary = new Dictionary<Type, Queue<object>>();
+
+        public object Fetch(Type type)
+        {
+	        Queue<object> queue;
+            if (!this.dictionary.TryGetValue(type, out queue))
+            {
+                queue = new Queue<object>();
+                this.dictionary.Add(type, queue);
+            }
+	        object obj;
+			if (queue.Count > 0)
+            {
+				obj = queue.Dequeue();
+            }
+			else
+			{
+				obj = Activator.CreateInstance(type);	
+			}
+            return obj;
+        }
+
+        public T Fetch<T>() where T: class
+		{
+            T t = (T) this.Fetch(typeof(T));
+			return t;
+		}
+        
+        public void Recycle(object obj)
+        {
+            Type type = obj.GetType();
+	        Queue<object> queue;
+            if (!this.dictionary.TryGetValue(type, out queue))
+            {
+                queue = new Queue<object>();
+				this.dictionary.Add(type, queue);
+            }
+            queue.Enqueue(obj);
+        }
+    }
+}

+ 3 - 0
Unity/Hotfix/UI/UILogin/Component/UILoginComponent.cs

@@ -62,6 +62,9 @@ namespace ETHotfix
 
 				Game.Scene.GetComponent<UIComponent>().Create(UIType.UILobby);
 				Game.Scene.GetComponent<UIComponent>().Remove(UIType.UILogin);
+
+				// 测试消息有成员是class类型
+				G2C_PlayerInfo g2CPlayerInfo = (G2C_PlayerInfo) await SessionComponent.Instance.Session.Call(new C2G_PlayerInfo());
 			}
 			catch (Exception e)
 			{

+ 1 - 0
Unity/Hotfix/Unity.Hotfix.csproj

@@ -92,6 +92,7 @@
     <Compile Include="Base\Object\Object.cs" />
     <Compile Include="Base\Object\EventSystem.cs" />
     <Compile Include="Base\Object\ObjectPool.cs" />
+    <Compile Include="Module\Message\MessagePool.cs" />
     <Compile Include="Module\Message\SessionComponent.cs" />
     <Compile Include="Module\Message\Session.cs" />
     <Compile Include="Module\UI\IUIFactory.cs" />

+ 2 - 0
Unity/Unity.csproj

@@ -342,6 +342,7 @@
     <Compile Include="Assets\Scripts\Entity\WWWAsync.cs" />
     <Compile Include="Assets\Scripts\Helper\ActionHelper.cs" />
     <Compile Include="Assets\Scripts\Helper\BundleHelper.cs" />
+    <Compile Include="Assets\Scripts\Helper\Dumper.cs" />
     <Compile Include="Assets\Scripts\Helper\GameObjectHelper.cs" />
     <Compile Include="Assets\Scripts\Helper\ILHelper.cs" />
     <Compile Include="Assets\Scripts\Helper\PathHelper.cs" />
@@ -388,6 +389,7 @@
     <Compile Include="Assets\Scripts\Module\Message\MessageDispatherComponent.cs" />
     <Compile Include="Assets\Scripts\Module\Message\MessageHandlerAttribute.cs" />
     <Compile Include="Assets\Scripts\Module\Message\MessageInfo.cs" />
+    <Compile Include="Assets\Scripts\Module\Message\MessagePool.cs" />
     <Compile Include="Assets\Scripts\Module\Message\MessageProxy.cs" />
     <Compile Include="Assets\Scripts\Module\Message\NetOuterComponent.cs" />
     <Compile Include="Assets\Scripts\Module\Message\Network\AChannel.cs" />

BIN
Unity/protoc.exe