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

Entity禁止定义方法,加上分析器限制

tanghai 3 лет назад
Родитель
Сommit
1d9677d175
33 измененных файлов с 1172 добавлено и 1524 удалено
  1. 1 0
      .gitignore
  2. 101 0
      Apps/Hotfix/Module/ActorLocation/LocationComponentSystem.cs
  3. 20 16
      Apps/Hotfix/Module/DB/DBComponentSystem.cs
  4. 30 0
      Apps/Hotfix/Server/GateSessionKeyComponentSystem.cs
  5. 15 0
      Apps/Hotfix/Server/PlayerSystem.cs
  6. 13 0
      Apps/Hotfix/Server/Unit/UnitGateComponentSystem.cs
  7. 3 112
      Apps/Model/Module/ActorLocation/LocationComponent.cs
  8. 0 10
      Apps/Model/Module/DB/DBComponent.cs
  9. 5 29
      Apps/Model/Server/GateSessionKeyComponent.cs
  10. 5 19
      Apps/Model/Server/Player.cs
  11. 5 18
      Apps/Model/Server/Unit/UnitGateComponent.cs
  12. 6 5
      Share/Analyzer/Analyzer/AddChildTypeAnalyzer.cs
  13. 7 1
      Share/Analyzer/Analyzer/EntityFiledAccessAnalyzer.cs
  14. 91 0
      Share/Analyzer/Analyzer/EntityMethodDeclarationAnalyzer.cs
  15. 3 3
      Share/Analyzer/Config/AnalyzeAssembly.cs
  16. 2 0
      Share/Analyzer/Config/DiagnosticIds.cs
  17. 1 0
      Unity/Codes/Model/Core/Entity/Scene.cs
  18. 13 0
      Unity/Codes/Model/Core/Object/EnableMethodAttribute.cs
  19. 33 29
      Unity/Codes/Model/Core/ObjectWait.cs
  20. 154 135
      Unity/Codes/Model/Core/Timer/TimerComponent.cs
  21. 81 75
      Unity/Codes/Model/Module/CoroutineLock/CoroutineLockComponent.cs
  22. 29 25
      Unity/Codes/Model/Module/CoroutineLock/CoroutineLockQueue.cs
  23. 25 28
      Unity/Codes/Model/Module/CoroutineLock/CoroutineLockQueueType.cs
  24. 73 73
      Unity/Codes/Model/Module/Message/OpcodeTypeComponent.cs
  25. 94 101
      Unity/Codes/Model/Module/Message/Session.cs
  26. 0 23
      Unity/Codes/Model/Module/Message/SessionCallbackComponent.cs
  27. 46 62
      Unity/Codes/Model/Module/Numeric/NumericComponent.cs
  28. 62 62
      Unity/Codes/Model/Module/Numeric/NumericWatcherComponent.cs
  29. 0 96
      Unity/Codes/Model/Module/UnityWebRequest/UnityWebRequestAsync.cs
  30. 0 352
      Unity/Codes/Model/Module/UnityWebRequest/UnityWebRequestRenewalAsync.cs
  31. 137 131
      Unity/Codes/ModelView/Client/Resource/ResourcesComponent.cs
  32. 47 43
      Unity/Codes/ModelView/Client/Resource/ResourcesLoaderComponent.cs
  33. 70 76
      Unity/Codes/ModelView/Module/UI/UI.cs

+ 1 - 0
.gitignore

@@ -58,3 +58,4 @@ Server/.DS_Store
 /Unity/Assembly-CSharp.csproj
 /Excel/~$*.xlsx
 /.vscode
+/Unity/UserSettings/Search.settings

+ 101 - 0
Apps/Hotfix/Module/ActorLocation/LocationComponentSystem.cs

@@ -0,0 +1,101 @@
+namespace ET
+{
+    [ObjectSystem]
+    public class LockInfoAwakeSystem: AwakeSystem<LockInfo, long, CoroutineLock>
+    {
+        public override void Awake(LockInfo self, long lockInstanceId, CoroutineLock coroutineLock)
+        {
+            self.CoroutineLock = coroutineLock;
+            self.LockInstanceId = lockInstanceId;
+        }
+    }
+    
+    [ObjectSystem]
+    public class LockInfoDestroySystem: DestroySystem<LockInfo>
+    {
+        public override void Destroy(LockInfo self)
+        {
+            self.CoroutineLock.Dispose();
+            self.LockInstanceId = 0;
+        }
+    }
+    
+    [FriendClass(typeof(LocationComponent))]
+    [FriendClass(typeof(LockInfo))]
+    public static class LocationComponentSystem
+    {
+        public static async ETTask Add(this LocationComponent self, long key, long instanceId)
+        {
+            using (await CoroutineLockComponent.Instance.Wait(CoroutineLockType.Location, key))
+            {
+                self.locations[key] = instanceId;
+                Log.Info($"location add key: {key} instanceId: {instanceId}");
+            }
+        }
+
+        public static async ETTask Remove(this LocationComponent self, long key)
+        {
+            using (await CoroutineLockComponent.Instance.Wait(CoroutineLockType.Location, key))
+            {
+                self.locations.Remove(key);
+                Log.Info($"location remove key: {key}");
+            }
+        }
+
+        public static async ETTask Lock(this LocationComponent self, long key, long instanceId, int time = 0)
+        {
+            CoroutineLock coroutineLock = await CoroutineLockComponent.Instance.Wait(CoroutineLockType.Location, key);
+
+            LockInfo lockInfo = self.AddChild<LockInfo, long, CoroutineLock>(instanceId, coroutineLock);
+            self.lockInfos.Add(key, lockInfo);
+
+            Log.Info($"location lock key: {key} instanceId: {instanceId}");
+
+            if (time > 0)
+            {
+                long lockInfoInstanceId = lockInfo.InstanceId;
+                await TimerComponent.Instance.WaitAsync(time);
+                if (lockInfo.InstanceId != lockInfoInstanceId)
+                {
+                    return;
+                }
+
+                self.UnLock(key, instanceId, instanceId);
+            }
+        }
+
+        public static void UnLock(this LocationComponent self, long key, long oldInstanceId, long newInstanceId)
+        {
+            if (!self.lockInfos.TryGetValue(key, out LockInfo lockInfo))
+            {
+                Log.Error($"location unlock not found key: {key} {oldInstanceId}");
+                return;
+            }
+
+            if (oldInstanceId != lockInfo.LockInstanceId)
+            {
+                Log.Error($"location unlock oldInstanceId is different: {key} {oldInstanceId}");
+                return;
+            }
+
+            Log.Info($"location unlock key: {key} instanceId: {oldInstanceId} newInstanceId: {newInstanceId}");
+
+            self.locations[key] = newInstanceId;
+
+            self.lockInfos.Remove(key);
+
+            // 解锁
+            lockInfo.Dispose();
+        }
+
+        public static async ETTask<long> Get(this LocationComponent self, long key)
+        {
+            using (await CoroutineLockComponent.Instance.Wait(CoroutineLockType.Location, key))
+            {
+                self.locations.TryGetValue(key, out long instanceId);
+                Log.Info($"location get key: {key} instanceId: {instanceId}");
+                return instanceId;
+            }
+        }
+    }
+}

+ 20 - 16
Apps/Hotfix/Module/DB/DBComponentSystem.cs

@@ -5,24 +5,28 @@ using MongoDB.Driver;
 
 namespace ET
 {
-	public class DBComponentAwakeSystem : AwakeSystem<DBComponent, string, string, int>
-	{
-		public override void Awake(DBComponent self, string dbConnection, string dbName, int zone)
-		{
-			self.mongoClient = new MongoClient(dbConnection);
-			self.database = self.mongoClient.GetDatabase(dbName);
-		}
-	}
-	
-    public class DBComponentDestroySystem: DestroySystem<DBComponent>
-    {
-        public override void Destroy(DBComponent self)
-        {
-        }
-    }
-	
+	[FriendClass(typeof(DBComponent))]
     public static class DBComponentSystem
     {
+	    public class DBComponentAwakeSystem : AwakeSystem<DBComponent, string, string, int>
+	    {
+		    public override void Awake(DBComponent self, string dbConnection, string dbName, int zone)
+		    {
+			    self.mongoClient = new MongoClient(dbConnection);
+			    self.database = self.mongoClient.GetDatabase(dbName);
+		    }
+	    }
+
+	    private static IMongoCollection<T> GetCollection<T>(this DBComponent self, string collection = null)
+	    {
+		    return self.database.GetCollection<T>(collection ?? typeof (T).Name);
+	    }
+
+	    private static IMongoCollection<Entity> GetCollection(this DBComponent self, string name)
+	    {
+		    return self.database.GetCollection<Entity>(name);
+	    }
+	    
 	    #region Query
 
 	    public static async ETTask<T> Query<T>(this DBComponent self, long id, string collection = null) where T : Entity

+ 30 - 0
Apps/Hotfix/Server/GateSessionKeyComponentSystem.cs

@@ -0,0 +1,30 @@
+namespace ET.Server
+{
+    [FriendClass(typeof(GateSessionKeyComponent))]
+    public static class GateSessionKeyComponentSystem
+    {
+        public static void Add(this GateSessionKeyComponent self, long key, string account)
+        {
+            self.sessionKey.Add(key, account);
+            self.TimeoutRemoveKey(key).Coroutine();
+        }
+
+        public static string Get(this GateSessionKeyComponent self, long key)
+        {
+            string account = null;
+            self.sessionKey.TryGetValue(key, out account);
+            return account;
+        }
+
+        public static void Remove(this GateSessionKeyComponent self, long key)
+        {
+            self.sessionKey.Remove(key);
+        }
+
+        private static async ETTask TimeoutRemoveKey(this GateSessionKeyComponent self, long key)
+        {
+            await TimerComponent.Instance.WaitAsync(20000);
+            self.sessionKey.Remove(key);
+        }
+    }
+}

+ 15 - 0
Apps/Hotfix/Server/PlayerSystem.cs

@@ -0,0 +1,15 @@
+namespace ET.Server
+{
+    [FriendClass(typeof(Player))]
+    public static class PlayerSystem
+    {
+        [ObjectSystem]
+        public class PlayerAwakeSystem : AwakeSystem<Player, string>
+        {
+            public override void Awake(Player self, string a)
+            {
+                self.Account = a;
+            }
+        }
+    }
+}

+ 13 - 0
Apps/Hotfix/Server/Unit/UnitGateComponentSystem.cs

@@ -0,0 +1,13 @@
+namespace ET.Server
+{
+    public static class UnitGateComponentSystem
+    {
+        public class UnitGateComponentAwakeSystem : AwakeSystem<UnitGateComponent, long>
+        {
+            public override void Awake(UnitGateComponent self, long a)
+            {
+                self.GateSessionActorId = a;
+            }
+        }
+    }
+}

+ 3 - 112
Apps/Model/Module/ActorLocation/LocationComponent.cs

@@ -2,127 +2,18 @@
 
 namespace ET
 {
-    [ObjectSystem]
-    public class LockInfoAwakeSystem: AwakeSystem<LockInfo, long, CoroutineLock>
-    {
-        public override void Awake(LockInfo self, long lockInstanceId, CoroutineLock coroutineLock)
-        {
-            self.CoroutineLock = coroutineLock;
-            self.LockInstanceId = lockInstanceId;
-        }
-    }
-
-    public class LockInfo: Entity, IAwake<long, CoroutineLock>
+    public class LockInfo: Entity, IAwake<long, CoroutineLock>, IDestroy
     {
         public long LockInstanceId;
 
         public CoroutineLock CoroutineLock;
-
-        public override void Dispose()
-        {
-            if (this.IsDisposed)
-            {
-                return;
-            }
-
-            base.Dispose();
-
-            this.CoroutineLock.Dispose();
-            LockInstanceId = 0;
-        }
     }
 
+    [ChildType(typeof(LockInfo))]
     public class LocationComponent: Entity, IAwake
     {
         public readonly Dictionary<long, long> locations = new Dictionary<long, long>();
 
-        private readonly Dictionary<long, LockInfo> lockInfos = new Dictionary<long, LockInfo>();
-
-        public async ETTask Add(long key, long instanceId)
-        {
-            using (await CoroutineLockComponent.Instance.Wait(CoroutineLockType.Location, key))
-            {
-                this.locations[key] = instanceId;
-                Log.Info($"location add key: {key} instanceId: {instanceId}");
-            }
-        }
-
-        public async ETTask Remove(long key)
-        {
-            using (await CoroutineLockComponent.Instance.Wait(CoroutineLockType.Location, key))
-            {
-                this.locations.Remove(key);
-                Log.Info($"location remove key: {key}");
-            }
-        }
-
-        public async ETTask Lock(long key, long instanceId, int time = 0)
-        {
-            CoroutineLock coroutineLock = await CoroutineLockComponent.Instance.Wait(CoroutineLockType.Location, key);
-
-            LockInfo lockInfo = this.AddChild<LockInfo, long, CoroutineLock>(instanceId, coroutineLock);
-            this.lockInfos.Add(key, lockInfo);
-
-            Log.Info($"location lock key: {key} instanceId: {instanceId}");
-
-            if (time > 0)
-            {
-                long lockInfoInstanceId = lockInfo.InstanceId;
-                await TimerComponent.Instance.WaitAsync(time);
-                if (lockInfo.InstanceId != lockInfoInstanceId)
-                {
-                    return;
-                }
-
-                UnLock(key, instanceId, instanceId);
-            }
-        }
-
-        public void UnLock(long key, long oldInstanceId, long newInstanceId)
-        {
-            if (!this.lockInfos.TryGetValue(key, out LockInfo lockInfo))
-            {
-                Log.Error($"location unlock not found key: {key} {oldInstanceId}");
-                return;
-            }
-
-            if (oldInstanceId != lockInfo.LockInstanceId)
-            {
-                Log.Error($"location unlock oldInstanceId is different: {key} {oldInstanceId}");
-                return;
-            }
-
-            Log.Info($"location unlock key: {key} instanceId: {oldInstanceId} newInstanceId: {newInstanceId}");
-
-            this.locations[key] = newInstanceId;
-
-            this.lockInfos.Remove(key);
-
-            // 解锁
-            lockInfo.Dispose();
-        }
-
-        public async ETTask<long> Get(long key)
-        {
-            using (await CoroutineLockComponent.Instance.Wait(CoroutineLockType.Location, key))
-            {
-                this.locations.TryGetValue(key, out long instanceId);
-                Log.Info($"location get key: {key} instanceId: {instanceId}");
-                return instanceId;
-            }
-        }
-
-        public override void Dispose()
-        {
-            if (this.IsDisposed)
-            {
-                return;
-            }
-
-            base.Dispose();
-
-            this.locations.Clear();
-            this.lockInfos.Clear();
-        }
+        public readonly Dictionary<long, LockInfo> lockInfos = new Dictionary<long, LockInfo>();
     }
 }

+ 0 - 10
Apps/Model/Module/DB/DBComponent.cs

@@ -11,15 +11,5 @@ namespace ET
 
         public MongoClient mongoClient;
         public IMongoDatabase database;
-
-        public IMongoCollection<T> GetCollection<T>(string collection = null)
-        {
-            return this.database.GetCollection<T>(collection ?? typeof (T).Name);
-        }
-
-        public IMongoCollection<Entity> GetCollection(string name)
-        {
-            return this.database.GetCollection<Entity>(name);
-        }
     }
 }

+ 5 - 29
Apps/Model/Server/GateSessionKeyComponent.cs

@@ -2,32 +2,8 @@
 
 namespace ET.Server
 {
-	public class GateSessionKeyComponent : Entity, IAwake
-	{
-		private readonly Dictionary<long, string> sessionKey = new Dictionary<long, string>();
-		
-		public void Add(long key, string account)
-		{
-			this.sessionKey.Add(key, account);
-			this.TimeoutRemoveKey(key).Coroutine();
-		}
-
-		public string Get(long key)
-		{
-			string account = null;
-			this.sessionKey.TryGetValue(key, out account);
-			return account;
-		}
-
-		public void Remove(long key)
-		{
-			this.sessionKey.Remove(key);
-		}
-
-		private async ETTask TimeoutRemoveKey(long key)
-		{
-			await TimerComponent.Instance.WaitAsync(20000);
-			this.sessionKey.Remove(key);
-		}
-	}
-}
+    public class GateSessionKeyComponent : Entity, IAwake
+    {
+        public readonly Dictionary<long, string> sessionKey = new Dictionary<long, string>();
+    }
+}

+ 5 - 19
Apps/Model/Server/Player.cs

@@ -1,23 +1,9 @@
 namespace ET.Server
 {
-	[ObjectSystem]
-	public class PlayerSystem : AwakeSystem<Player, string>
-	{
-		public override void Awake(Player self, string a)
-		{
-			self.Awake(a);
-		}
-	}
-
-	public sealed class Player : Entity, IAwake<string>
-	{
-		public string Account { get; private set; }
+    public sealed class Player : Entity, IAwake<string>
+    {
+        public string Account { get; set; }
 		
-		public long UnitId { get; set; }
-
-		public void Awake(string account)
-		{
-			this.Account = account;
-		}
-	}
+        public long UnitId { get; set; }
+    }
 }

+ 5 - 18
Apps/Model/Server/Unit/UnitGateComponent.cs

@@ -1,20 +1,7 @@
-namespace ET.Server
+namespace ET
 {
-	public class UnitGateComponentAwakeSystem : AwakeSystem<UnitGateComponent, long>
-	{
-		public override void Awake(UnitGateComponent self, long a)
-		{
-			self.Awake(a);
-		}
-	}
-
-	public class UnitGateComponent : Entity, IAwake<long>, ITransfer
-	{
-		public long GateSessionActorId { get; private set; }
-
-		public void Awake(long gateSessionId)
-		{
-			this.GateSessionActorId = gateSessionId;
-		}
-	}
+    public class UnitGateComponent : Entity, IAwake<long>, ITransfer
+    {
+        public long GateSessionActorId { get; set; }
+    }
 }

+ 6 - 5
Share/Analyzer/Analyzer/AddChildTypeAnalyzer.cs

@@ -18,7 +18,7 @@ namespace ET.Analyzer
         private const string Description = "请使用被允许的ChildType 或添加该类型至ChildType.";
 
         private static readonly string[] AddChildMethods = { "AddChild", "AddChildWithId" };
-
+        
         private const string EntityType = "ET.Entity";
 
         private static readonly DiagnosticDescriptor Rule =
@@ -72,13 +72,13 @@ namespace ET.Analyzer
 
             // 获取AddChild函数的调用者类型
             ITypeSymbol? parentTypeSymbol = memberAccessExpressionSyntax.GetMemberAccessSyntaxParentType(context.SemanticModel);
-            if (parentTypeSymbol == null)
+            if (parentTypeSymbol==null)
             {
                 return;
             }
 
             // 只检查Entity的子类
-            if (parentTypeSymbol.BaseType?.ToString() != EntityType)
+            if (parentTypeSymbol.BaseType?.ToString()!= EntityType)
             {
                 return;
             }
@@ -99,8 +99,8 @@ namespace ET.Analyzer
                     availableChildTypeSymbol = s;
                 }
             }
-
-            if (hasChildTypeAttribute && availableChildTypeSymbol == null)
+            
+            if (hasChildTypeAttribute &&(availableChildTypeSymbol==null))
             {
                 return;
             }
@@ -180,6 +180,7 @@ namespace ET.Analyzer
                 return;
             }
 
+            
             // 判断child类型是否属于约束类型
             if (availableChildTypeSymbol?.ToString() == childTypeSymbol.ToString())
             {

+ 7 - 1
Share/Analyzer/Analyzer/EntityFiledAccessAnalyzer.cs

@@ -46,7 +46,7 @@ namespace ET.Analyzer
 
         private void AnalyzeMemberAccessExpression(SyntaxNodeAnalysisContext context)
         {
-            if (!AnalyzerHelper.IsAssemblyNeedAnalyze(context.Compilation.AssemblyName, AnalyzeAssembly.AllHotfix))
+            if (!AnalyzerHelper.IsAssemblyNeedAnalyze(context.Compilation.AssemblyName, AnalyzeAssembly.All))
             {
                 return;
             }
@@ -96,6 +96,12 @@ namespace ET.Analyzer
                 return;
             }
 
+            // 允许类内部访问字段
+            if (accessFieldClassSymbol.ToString()== filedSymbol.ContainingType.ToString() )
+            {
+                return;
+            }
+            
             //判断是否在实体类生命周期System中
             if (this.CheckIsEntityLifecycleSystem(accessFieldClassSymbol, filedSymbol.ContainingType))
             {

+ 91 - 0
Share/Analyzer/Analyzer/EntityMethodDeclarationAnalyzer.cs

@@ -0,0 +1,91 @@
+using System.Collections.Immutable;
+using System.Linq;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
+
+namespace ET.Analyzer
+{
+    [DiagnosticAnalyzer(LanguageNames.CSharp)]
+    public class EntityMethodDeclarationAnalyzer : DiagnosticAnalyzer
+    {
+        private const string Title = "实体类禁止声明方法";
+
+        private const string MessageFormat = "实体类: {0} 不能在类内部声明方法: {1}";
+
+        private const string Description = "实体类禁止声明方法.";
+        
+        private const string EntityType = "ET.Entity";
+
+        private const string EnableMethodAttribute = "ET.EnableMethodAttribute";
+        
+        private static readonly DiagnosticDescriptor Rule =
+                new DiagnosticDescriptor(DiagnosticIds.EntityMethodDeclarationAnalyzerRuleId,
+                    Title,
+                    MessageFormat,
+                    DiagnosticCategories.Hotfix,
+                    DiagnosticSeverity.Error,
+                    true,
+                    Description);
+
+        public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);
+        
+        public override void Initialize(AnalysisContext context)
+        {
+            if (!AnalyzerGlobalSetting.EnableAnalyzer)
+            {
+                return;
+            }
+
+            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
+            context.EnableConcurrentExecution();
+            context.RegisterSymbolAction(this.Analyzer, SymbolKind.NamedType);
+        }
+
+        private void Analyzer(SymbolAnalysisContext context)
+        {
+            if (!AnalyzerHelper.IsAssemblyNeedAnalyze(context.Compilation.AssemblyName, AnalyzeAssembly.AllModel))
+            {
+                return;
+            }
+            
+            if (!(context.Symbol is INamedTypeSymbol namedTypeSymbol))
+            {
+                return;
+            }
+
+            // 筛选出实体类
+            if (namedTypeSymbol.BaseType?.ToString() != EntityType)
+            {
+                return;
+            }
+
+            // 忽略含有EnableMethod标签的实体类
+            if (namedTypeSymbol.HasAttribute(EnableMethodAttribute))
+            {
+                return;
+            }
+
+            foreach (var syntaxReference in namedTypeSymbol.DeclaringSyntaxReferences)
+            {
+                var classSyntax = syntaxReference.GetSyntax();
+                if (!(classSyntax is ClassDeclarationSyntax classDeclarationSyntax))
+                {
+                    return;
+                }
+
+                foreach (var memberDeclarationSyntax in classDeclarationSyntax.Members)
+                {
+                    // 筛选出类声明语法节点下的所有方法声明语法节点
+                    if (memberDeclarationSyntax is MethodDeclarationSyntax methodDeclarationSyntax)
+                    {
+                        Diagnostic diagnostic = Diagnostic.Create(Rule, methodDeclarationSyntax.GetLocation(),namedTypeSymbol.Name,methodDeclarationSyntax.Identifier.Text);
+                        context.ReportDiagnostic(diagnostic);
+                    }
+                }
+            }
+            
+        }
+    }
+}

+ 3 - 3
Share/Analyzer/Config/AnalyzeAssembly.cs

@@ -4,7 +4,7 @@
     {
         public const string ServerModel = "Model";
 
-        public const string SerVerHotfix = "Hotfix";
+        public const string ServerHotfix = "Hotfix";
 
         public const string UnityModel = "Unity.Model";
 
@@ -14,10 +14,10 @@
 
         public const string UnityHotfixView = "Unity.HotfixView";
 
-        public static readonly string[] AllHotfix = { SerVerHotfix, UnityHotfix, UnityHotfixView };
+        public static readonly string[] AllHotfix = { ServerHotfix, UnityHotfix, UnityHotfixView };
 
         public static readonly string[] AllModel = { ServerModel, UnityModel, UnityModelView };
 
-        public static readonly string[] All = { ServerModel, SerVerHotfix, UnityModel, UnityHotfix, UnityModelView, UnityHotfixView };
+        public static readonly string[] All = { ServerModel, ServerHotfix, UnityModel, UnityHotfix, UnityModelView, UnityHotfixView };
     }
 }

+ 2 - 0
Share/Analyzer/Config/DiagnosticIds.cs

@@ -11,5 +11,7 @@
         public const string HotfixProjectFieldDeclarationAnalyzerRuleId = "ET00004";
 
         public const string ClassDeclarationInHotfixAnalyzerRuleId = "ET00005";
+        
+        public const string EntityMethodDeclarationAnalyzerRuleId = "ET00006";
     }
 }

+ 1 - 0
Unity/Codes/Model/Core/Entity/Scene.cs

@@ -1,5 +1,6 @@
 namespace ET
 {
+    [EnableMethod]
     public sealed class Scene: Entity
     {
         public int Zone

+ 13 - 0
Unity/Codes/Model/Core/Object/EnableMethodAttribute.cs

@@ -0,0 +1,13 @@
+using System;
+
+namespace ET
+{
+    /// <summary>
+    /// 对于特殊实体类 允许类内部声明方法的标签
+    /// </summary>
+    [AttributeUsage(AttributeTargets.Class, Inherited = false)]
+    public class EnableMethodAttribute : Attribute
+    {
+        
+    }
+}

+ 33 - 29
Unity/Codes/Model/Core/ObjectWait.cs

@@ -21,35 +21,36 @@ namespace ET
         }
     }
 
-    [ObjectSystem]
-    public class ObjectWaitAwakeSystem: AwakeSystem<ObjectWait>
+    [FriendClass(typeof(ObjectWait))]
+    public static class ObjectWaitSystem
     {
-        public override void Awake(ObjectWait self)
+        [ObjectSystem]
+        public class ObjectWaitAwakeSystem: AwakeSystem<ObjectWait>
         {
-            self.tcss.Clear();
+            public override void Awake(ObjectWait self)
+            {
+                self.tcss.Clear();
+            }
         }
-    }
 
-    [ObjectSystem]
-    public class ObjectWaitDestroySystem: DestroySystem<ObjectWait>
-    {
-        public override void Destroy(ObjectWait self)
+        [ObjectSystem]
+        public class ObjectWaitDestroySystem: DestroySystem<ObjectWait>
         {
-            foreach (object v in self.tcss.Values.ToArray())
+            public override void Destroy(ObjectWait self)
             {
-                ((ObjectWait.IDestroyRun) v).SetResult();
+                foreach (object v in self.tcss.Values.ToArray())
+                {
+                    ((IDestroyRun) v).SetResult();
+                }
             }
         }
-    }
 
-    public class ObjectWait: Entity, IAwake, IDestroy
-    {
-        public interface IDestroyRun
+        private interface IDestroyRun
         {
             void SetResult();
         }
 
-        public class ResultCallback<K>: IDestroyRun where K : struct, IWaitType
+        private class ResultCallback<K>: IDestroyRun where K : struct, IWaitType
         {
             private ETTask<K> tcs;
 
@@ -82,18 +83,16 @@ namespace ET
                 t.SetResult(new K() { Error = WaitTypeError.Destroy });
             }
         }
-
-        public Dictionary<Type, object> tcss = new Dictionary<Type, object>();
-
-        public async ETTask<T> Wait<T>(ETCancellationToken cancellationToken = null) where T : struct, IWaitType
+        
+        public static async ETTask<T> Wait<T>(this ObjectWait self, ETCancellationToken cancellationToken = null) where T : struct, IWaitType
         {
             ResultCallback<T> tcs = new ResultCallback<T>();
             Type type = typeof (T);
-            this.tcss.Add(type, tcs);
+            self.tcss.Add(type, tcs);
 
             void CancelAction()
             {
-                this.Notify(new T() { Error = WaitTypeError.Cancel });
+                self.Notify(new T() { Error = WaitTypeError.Cancel });
             }
 
             T ret;
@@ -109,7 +108,7 @@ namespace ET
             return ret;
         }
 
-        public async ETTask<T> Wait<T>(int timeout, ETCancellationToken cancellationToken = null) where T : struct, IWaitType
+        public static async ETTask<T> Wait<T>(this ObjectWait self, int timeout, ETCancellationToken cancellationToken = null) where T : struct, IWaitType
         {
             ResultCallback<T> tcs = new ResultCallback<T>();
             async ETTask WaitTimeout()
@@ -123,16 +122,16 @@ namespace ET
                 {
                     return;
                 }
-                Notify(new T() { Error = WaitTypeError.Timeout });
+                self.Notify(new T() { Error = WaitTypeError.Timeout });
             }
             
             WaitTimeout().Coroutine();
             
-            this.tcss.Add(typeof (T), tcs);
+            self.tcss.Add(typeof (T), tcs);
             
             void CancelAction()
             {
-                Notify(new T() { Error = WaitTypeError.Cancel });
+                self.Notify(new T() { Error = WaitTypeError.Cancel });
             }
             
             T ret;
@@ -148,16 +147,21 @@ namespace ET
             return ret;
         }
 
-        public void Notify<T>(T obj) where T : struct, IWaitType
+        public static void Notify<T>(this ObjectWait self, T obj) where T : struct, IWaitType
         {
             Type type = typeof (T);
-            if (!this.tcss.TryGetValue(type, out object tcs))
+            if (!self.tcss.TryGetValue(type, out object tcs))
             {
                 return;
             }
 
-            this.tcss.Remove(type);
+            self.tcss.Remove(type);
             ((ResultCallback<T>) tcs).SetResult(obj);
         }
     }
+
+    public class ObjectWait: Entity, IAwake, IDestroy
+    {
+        public Dictionary<Type, object> tcss = new Dictionary<Type, object>();
+    }
 }

+ 154 - 135
Unity/Codes/Model/Core/Timer/TimerComponent.cs

@@ -46,70 +46,97 @@ namespace ET
         public int Type;
     }
 
-    [ObjectSystem]
-    public class TimerComponentAwakeSystem: AwakeSystem<TimerComponent>
+    [FriendClass(typeof(TimerAction))]
+    [FriendClass(typeof(TimerComponent))]
+    public static class TimerComponentSystem
     {
-        public override void Awake(TimerComponent self)
+        [ObjectSystem]
+        public class TimerComponentAwakeSystem: AwakeSystem<TimerComponent>
         {
-            TimerComponent.Instance = self;
-            self.Awake();
+            public override void Awake(TimerComponent self)
+            {
+                TimerComponent.Instance = self;
+                self.Init();
+            }
         }
-    }
 
-    [ObjectSystem]
-    public class TimerComponentUpdateSystem: UpdateSystem<TimerComponent>
-    {
-        public override void Update(TimerComponent self)
+        [ObjectSystem]
+        public class TimerComponentUpdateSystem: UpdateSystem<TimerComponent>
         {
-            self.Update();
-        }
-    }
-    
-    [ObjectSystem]
-    public class TimerComponentLoadSystem: LoadSystem<TimerComponent>
-    {
-        public override void Load(TimerComponent self)
-        {
-            self.Awake();
-        }
-    }
+            public override void Update(TimerComponent self)
+            {
+                if (self.TimeId.Count == 0)
+                {
+                    return;
+                }
 
-    [ObjectSystem]
-    public class TimerComponentDestroySystem: DestroySystem<TimerComponent>
-    {
-        public override void Destroy(TimerComponent self)
-        {
-            TimerComponent.Instance = null;
-        }
-    }
+                long timeNow = TimeHelper.ServerNow();
 
-    public class TimerComponent: Entity, IAwake, IUpdate, ILoad, IDestroy
-    {
-        public static TimerComponent Instance
-        {
-            get;
-            set;
-        }
+                if (timeNow < self.minTime)
+                {
+                    return;
+                }
 
-        /// <summary>
-        /// key: time, value: timer id
-        /// </summary>
-        private readonly MultiMap<long, long> TimeId = new MultiMap<long, long>();
+                foreach (KeyValuePair<long, List<long>> kv in self.TimeId)
+                {
+                    long k = kv.Key;
+                    if (k > timeNow)
+                    {
+                        self.minTime = k;
+                        break;
+                    }
 
-        private readonly Queue<long> timeOutTime = new Queue<long>();
+                    self.timeOutTime.Enqueue(k);
+                }
 
-        private readonly Queue<long> timeOutTimerIds = new Queue<long>();
+                while (self.timeOutTime.Count > 0)
+                {
+                    long time = self.timeOutTime.Dequeue();
+                    var list = self.TimeId[time];
+                    for (int i = 0; i < list.Count; ++i)
+                    {
+                        long timerId = list[i];
+                        self.timeOutTimerIds.Enqueue(timerId);
+                    }
 
-        // 记录最小时间,不用每次都去MultiMap取第一个值
-        private long minTime;
+                    self.TimeId.Remove(time);
+                }
+
+                while (self.timeOutTimerIds.Count > 0)
+                {
+                    long timerId = self.timeOutTimerIds.Dequeue();
 
-        private const int TimeTypeMax = 10000;
+                    TimerAction timerAction = self.GetChild<TimerAction>(timerId);
+                    if (timerAction == null)
+                    {
+                        continue;
+                    }
+                    self.Run(timerAction);
+                }
+            }
+        }
+    
+        [ObjectSystem]
+        public class TimerComponentLoadSystem: LoadSystem<TimerComponent>
+        {
+            public override void Load(TimerComponent self)
+            {
+                self.Init();
+            }
+        }
 
-        private ITimer[] timerActions;
+        [ObjectSystem]
+        public class TimerComponentDestroySystem: DestroySystem<TimerComponent>
+        {
+            public override void Destroy(TimerComponent self)
+            {
+                TimerComponent.Instance = null;
+            }
+        }
 
-        public void Awake()
+        private static void Init(this TimerComponent self)
         {
-            this.timerActions = new ITimer[TimeTypeMax];
+            self.timerActions = new ITimer[TimerComponent.TimeTypeMax];
 
             HashSet<Type> types = Game.EventSystem.GetTypes(typeof (TimerAttribute));
 
@@ -131,69 +158,19 @@ namespace ET
                 foreach (object attr in attrs)
                 {
                     TimerAttribute timerAttribute = attr as TimerAttribute;
-                    this.timerActions[timerAttribute.Type] = iTimer;
-                }
-            }
-        }
-
-        public void Update()
-        {
-            if (this.TimeId.Count == 0)
-            {
-                return;
-            }
-
-            long timeNow = TimeHelper.ServerNow();
-
-            if (timeNow < this.minTime)
-            {
-                return;
-            }
-
-            foreach (KeyValuePair<long, List<long>> kv in this.TimeId)
-            {
-                long k = kv.Key;
-                if (k > timeNow)
-                {
-                    minTime = k;
-                    break;
-                }
-
-                this.timeOutTime.Enqueue(k);
-            }
-
-            while (this.timeOutTime.Count > 0)
-            {
-                long time = this.timeOutTime.Dequeue();
-                foreach (long timerId in this.TimeId[time])
-                {
-                    this.timeOutTimerIds.Enqueue(timerId);
-                }
-
-                this.TimeId.Remove(time);
-            }
-
-            while (this.timeOutTimerIds.Count > 0)
-            {
-                long timerId = this.timeOutTimerIds.Dequeue();
-
-                TimerAction timerAction = this.GetChild<TimerAction>(timerId);
-                if (timerAction == null)
-                {
-                    continue;
+                    self.timerActions[timerAttribute.Type] = iTimer;
                 }
-                Run(timerAction);
             }
         }
 
-        private void Run(TimerAction timerAction)
+        private static void Run(this TimerComponent self, TimerAction timerAction)
         {
             switch (timerAction.TimerClass)
             {
                 case TimerClass.OnceTimer:
                 {
                     int type = timerAction.Type;
-                    ITimer timer = this.timerActions[type];
+                    ITimer timer = self.timerActions[type];
                     if (timer == null)
                     {
                         Log.Error($"not found timer action: {type}");
@@ -205,7 +182,7 @@ namespace ET
                 case TimerClass.OnceWaitTimer:
                 {
                     ETTask<bool> tcs = timerAction.Object as ETTask<bool>;
-                    this.Remove(timerAction.Id);
+                    self.Remove(timerAction.Id);
                     tcs.SetResult(true);
                     break;
                 }
@@ -213,9 +190,9 @@ namespace ET
                 {
                     int type = timerAction.Type;
                     long tillTime = TimeHelper.ServerNow() + timerAction.Time;
-                    this.AddTimer(tillTime, timerAction);
+                    self.AddTimer(tillTime, timerAction);
 
-                    ITimer timer = this.timerActions[type];
+                    ITimer timer = self.timerActions[type];
                     if (timer == null)
                     {
                         Log.Error($"not found timer action: {type}");
@@ -227,30 +204,35 @@ namespace ET
             }
         }
         
-        private void AddTimer(long tillTime, TimerAction timer)
+        private static void AddTimer(this TimerComponent self, long tillTime, TimerAction timer)
         {
-            this.TimeId.Add(tillTime, timer.Id);
-            if (tillTime < this.minTime)
+            if (timer.TimerClass == TimerClass.RepeatedTimer && timer.Time == 0)
+            {
+                self.everyFrameTimer.Enqueue(timer.Id);
+                return;
+            }
+            self.TimeId.Add(tillTime, timer.Id);
+            if (tillTime < self.minTime)
             {
-                this.minTime = tillTime;
+                self.minTime = tillTime;
             }
         }
 
-        public bool Remove(ref long id)
+        public static bool Remove(this TimerComponent self, ref long id)
         {
             long i = id;
             id = 0;
-            return this.Remove(i);
+            return self.Remove(i);
         }
         
-        private bool Remove(long id)
+        private static bool Remove(this TimerComponent self, long id)
         {
             if (id == 0)
             {
                 return false;
             }
 
-            TimerAction timerAction = this.GetChild<TimerAction>(id);
+            TimerAction timerAction = self.GetChild<TimerAction>(id);
             if (timerAction == null)
             {
                 return false;
@@ -259,7 +241,7 @@ namespace ET
             return true;
         }
 
-        public async ETTask<bool> WaitTillAsync(long tillTime, ETCancellationToken cancellationToken = null)
+        public static async ETTask<bool> WaitTillAsync(this TimerComponent self, long tillTime, ETCancellationToken cancellationToken = null)
         {
             long timeNow = TimeHelper.ServerNow();
             if (timeNow >= tillTime)
@@ -268,13 +250,13 @@ namespace ET
             }
 
             ETTask<bool> tcs = ETTask<bool>.Create(true);
-            TimerAction timer = this.AddChild<TimerAction, TimerClass, long, int, object>(TimerClass.OnceWaitTimer, tillTime - timeNow, 0, tcs, true);
-            this.AddTimer(tillTime, timer);
+            TimerAction timer = self.AddChild<TimerAction, TimerClass, long, int, object>(TimerClass.OnceWaitTimer, tillTime - timeNow, 0, tcs, true);
+            self.AddTimer(tillTime, timer);
             long timerId = timer.Id;
 
             void CancelAction()
             {
-                if (this.Remove(timerId))
+                if (self.Remove(timerId))
                 {
                     tcs.SetResult(false);
                 }
@@ -293,12 +275,13 @@ namespace ET
             return ret;
         }
 
-        public async ETTask<bool> WaitFrameAsync(ETCancellationToken cancellationToken = null)
+        public static async ETTask<bool> WaitFrameAsync(this TimerComponent self, ETCancellationToken cancellationToken = null)
         {
-            return await WaitAsync(1, cancellationToken);
+            bool ret = await self.WaitAsync(1, cancellationToken);
+            return ret;
         }
 
-        public async ETTask<bool> WaitAsync(long time, ETCancellationToken cancellationToken = null)
+        public static async ETTask<bool> WaitAsync(this TimerComponent self, long time, ETCancellationToken cancellationToken = null)
         {
             if (time == 0)
             {
@@ -308,13 +291,13 @@ namespace ET
 
             ETTask<bool> tcs = ETTask<bool>.Create(true);
             
-            TimerAction timer = this.AddChild<TimerAction, TimerClass, long, int, object>(TimerClass.OnceWaitTimer, time, 0, tcs, true);
-            this.AddTimer(tillTime, timer);
+            TimerAction timer = self.AddChild<TimerAction, TimerClass, long, int, object>(TimerClass.OnceWaitTimer, time, 0, tcs, true);
+            self.AddTimer(tillTime, timer);
             long timerId = timer.Id;
 
             void CancelAction()
             {
-                if (this.Remove(timerId))
+                if (self.Remove(timerId))
                 {
                     tcs.SetResult(false);
                 }
@@ -336,46 +319,82 @@ namespace ET
         // 用这个优点是可以热更,缺点是回调式的写法,逻辑不连贯。WaitTillAsync不能热更,优点是逻辑连贯。
         // wait时间短并且逻辑需要连贯的建议WaitTillAsync
         // wait时间长不需要逻辑连贯的建议用NewOnceTimer
-        public long NewOnceTimer(long tillTime, int type, object args)
+        public static long NewOnceTimer(this TimerComponent self, long tillTime, int type, object args)
         {
             if (tillTime < TimeHelper.ServerNow())
             {
                 Log.Warning($"new once time too small: {tillTime}");
             }
-            TimerAction timer = this.AddChild<TimerAction, TimerClass, long, int, object>(TimerClass.OnceTimer, tillTime, type, args, true);
-            this.AddTimer(tillTime, timer);
+            TimerAction timer = self.AddChild<TimerAction, TimerClass, long, int, object>(TimerClass.OnceTimer, tillTime, type, args, true);
+            self.AddTimer(tillTime, timer);
             return timer.Id;
         }
 
-        public long NewFrameTimer(int type, object args)
+        public static long NewFrameTimer(this TimerComponent self, int type, object args)
         {
 #if NOT_UNITY
-			return NewRepeatedTimerInner(100, type, args);
+			return self.NewRepeatedTimerInner(100, type, args);
 #else
-            return NewRepeatedTimerInner(1, type, args);
+            return self.NewRepeatedTimerInner(0, type, args);
 #endif
         }
 
         /// <summary>
         /// 创建一个RepeatedTimer
         /// </summary>
-        private long NewRepeatedTimerInner(long time, int type, object args)
+        private static long NewRepeatedTimerInner(this TimerComponent self, long time, int type, object args)
         {
 #if NOT_UNITY
 			if (time < 100)
-			{
+			{ 
 				throw new Exception($"repeated timer < 100, timerType: time: {time}");
 			}
 #endif
             long tillTime = TimeHelper.ServerNow() + time;
-            TimerAction timer = this.AddChild<TimerAction, TimerClass, long, int, object>(TimerClass.RepeatedTimer, time, type, args, true);
-            this.AddTimer(tillTime, timer);
+            TimerAction timer = self.AddChild<TimerAction, TimerClass, long, int, object>(TimerClass.RepeatedTimer, time, type, args, true);
+
+            // 每帧执行的不用加到timerId中,防止遍历
+            self.AddTimer(tillTime, timer);
             return timer.Id;
         }
 
-        public long NewRepeatedTimer(long time, int type, object args)
+        public static long NewRepeatedTimer(this TimerComponent self, long time, int type, object args)
+        {
+            if (time < 100)
+            {
+                Log.Error($"time too small: {time}");
+                return 0;
+            }
+            return self.NewRepeatedTimerInner(time, type, args);
+        }
+    }
+
+    
+
+    public class TimerComponent: Entity, IAwake, IUpdate, ILoad, IDestroy
+    {
+        public static TimerComponent Instance
         {
-            return NewRepeatedTimerInner(time, type, args);
+            get;
+            set;
         }
+        
+        /// <summary>
+        /// key: time, value: timer id
+        /// </summary>
+        public readonly MultiMap<long, long> TimeId = new MultiMap<long, long>();
+
+        public readonly Queue<long> timeOutTime = new Queue<long>();
+
+        public readonly Queue<long> timeOutTimerIds = new Queue<long>();
+        
+        public readonly Queue<long> everyFrameTimer = new Queue<long>();
+
+        // 记录最小时间,不用每次都去MultiMap取第一个值
+        public long minTime;
+
+        public const int TimeTypeMax = 10000;
+
+        public ITimer[] timerActions;
     }
 }

+ 81 - 75
Unity/Codes/Model/Module/CoroutineLock/CoroutineLockComponent.cs

@@ -1,110 +1,116 @@
+using System;
 using System.Collections.Generic;
 
 namespace ET
 {
-    [ObjectSystem]
-    public class CoroutineLockComponentAwakeSystem: AwakeSystem<CoroutineLockComponent>
+    [FriendClass(typeof (CoroutineLockComponent))]
+    public static class CoroutineLockComponentSystem
     {
-        public override void Awake(CoroutineLockComponent self)
+        [ObjectSystem]
+        public class CoroutineLockComponentAwakeSystem: AwakeSystem<CoroutineLockComponent>
         {
-            CoroutineLockComponent.Instance = self;
-            
-            self.list = new List<CoroutineLockQueueType>(CoroutineLockType.Max);
-            for (int i = 0; i < CoroutineLockType.Max; ++i)
+            public override void Awake(CoroutineLockComponent self)
             {
-                CoroutineLockQueueType coroutineLockQueueType = self.AddChildWithId<CoroutineLockQueueType>(++self.idGenerator);
-                self.list.Add(coroutineLockQueueType);
-            }
-        }
-    }
+                CoroutineLockComponent.Instance = self;
 
-    [ObjectSystem]
-    public class CoroutineLockComponentDestroySystem: DestroySystem<CoroutineLockComponent>
-    {
-        public override void Destroy(CoroutineLockComponent self)
-        {
-            self.list.Clear();
-            self.nextFrameRun.Clear();
-            self.timers.Clear();
-            self.timeOutIds.Clear();
-            self.timerOutTimer.Clear();
-            self.idGenerator = 0;
-            self.minTime = 0;
+                self.list = new List<CoroutineLockQueueType>(CoroutineLockType.Max);
+                for (int i = 0; i < CoroutineLockType.Max; ++i)
+                {
+                    CoroutineLockQueueType coroutineLockQueueType = self.AddChildWithId<CoroutineLockQueueType>(++self.idGenerator);
+                    self.list.Add(coroutineLockQueueType);
+                }
+            }
         }
-    }
 
-    public class CoroutineLockComponentUpdateSystem: UpdateSystem<CoroutineLockComponent>
-    {
-        public override void Update(CoroutineLockComponent self)
+        [ObjectSystem]
+        public class CoroutineLockComponentDestroySystem: DestroySystem<CoroutineLockComponent>
         {
-            // 检测超时的CoroutineLock
-            TimeoutCheck(self);
-            
-            // 循环过程中会有对象继续加入队列
-            while(self.nextFrameRun.Count > 0)
+            public override void Destroy(CoroutineLockComponent self)
             {
-                (int coroutineLockType, long key, int count) = self.nextFrameRun.Dequeue();
-                self.Notify(coroutineLockType, key, count);
+                self.list.Clear();
+                self.nextFrameRun.Clear();
+                self.timers.Clear();
+                self.timeOutIds.Clear();
+                self.timerOutTimer.Clear();
+                self.idGenerator = 0;
+                self.minTime = 0;
             }
         }
 
-        private void TimeoutCheck(CoroutineLockComponent self)
+        [FriendClass(typeof (CoroutineLock))]
+        public class CoroutineLockComponentUpdateSystem: UpdateSystem<CoroutineLockComponent>
         {
-            // 超时的锁
-            if (self.timers.Count == 0)
+            public override void Update(CoroutineLockComponent self)
             {
-                return;
-            }
-
-            long timeNow = TimeHelper.ClientFrameTime();
+                // 检测超时的CoroutineLock
+                TimeoutCheck(self);
 
-            if (timeNow < self.minTime)
-            {
-                return;
+                // 循环过程中会有对象继续加入队列
+                while (self.nextFrameRun.Count > 0)
+                {
+                    (int coroutineLockType, long key, int count) = self.nextFrameRun.Dequeue();
+                    self.Notify(coroutineLockType, key, count);
+                }
             }
 
-            foreach (KeyValuePair<long, List<CoroutineLockTimer>> kv in self.timers)
+            private void TimeoutCheck(CoroutineLockComponent self)
             {
-                long k = kv.Key;
-                if (k > timeNow)
+                // 超时的锁
+                if (self.timers.Count == 0)
                 {
-                    self.minTime = k;
-                    break;
+                    return;
                 }
 
-                self.timeOutIds.Enqueue(k);
-            }
-            
-            self.timerOutTimer.Clear();
-            
-            while (self.timeOutIds.Count > 0)
-            {
-                long time = self.timeOutIds.Dequeue();
-                foreach (CoroutineLockTimer coroutineLockTimer in self.timers[time])
+                long timeNow = TimeHelper.ClientFrameTime();
+
+                if (timeNow < self.minTime)
                 {
-                    self.timerOutTimer.Enqueue(coroutineLockTimer);
+                    return;
+                }
+
+                foreach (KeyValuePair<long, List<CoroutineLockTimer>> kv in self.timers)
+                {
+                    long k = kv.Key;
+                    if (k > timeNow)
+                    {
+                        self.minTime = k;
+                        break;
+                    }
+
+                    self.timeOutIds.Enqueue(k);
                 }
-                self.timers.Remove(time);
-            }
             
-            while (self.timerOutTimer.Count > 0)
-            {
-                CoroutineLockTimer coroutineLockTimer = self.timerOutTimer.Dequeue();
-                if (coroutineLockTimer.CoroutineLockInstanceId != coroutineLockTimer.CoroutineLock.InstanceId)
+                self.timerOutTimer.Clear();
+
+                while (self.timeOutIds.Count > 0)
                 {
-                    continue;
+                    long time = self.timeOutIds.Dequeue();
+                    var list = self.timers[time];
+                    for (int i = 0; i < list.Count; ++i)
+                    {
+                        CoroutineLockTimer coroutineLockTimer = list[i];
+                        self.timerOutTimer.Enqueue(coroutineLockTimer);
+                    }
+
+                    self.timers.Remove(time);
                 }
 
-                CoroutineLock coroutineLock = coroutineLockTimer.CoroutineLock;
-                // 超时直接调用下一个锁
-                self.RunNextCoroutine(coroutineLock.coroutineLockType, coroutineLock.key, coroutineLock.level + 1);
-                coroutineLock.coroutineLockType = CoroutineLockType.None; // 上面调用了下一个, dispose不再调用
+                while (self.timerOutTimer.Count > 0)
+                {
+                    CoroutineLockTimer coroutineLockTimer = self.timerOutTimer.Dequeue();
+                    if (coroutineLockTimer.CoroutineLockInstanceId != coroutineLockTimer.CoroutineLock.InstanceId)
+                    {
+                        continue;
+                    }
+
+                    CoroutineLock coroutineLock = coroutineLockTimer.CoroutineLock;
+                    // 超时直接调用下一个锁
+                    self.RunNextCoroutine(coroutineLock.coroutineLockType, coroutineLock.key, coroutineLock.level + 1);
+                    coroutineLock.coroutineLockType = CoroutineLockType.None; // 上面调用了下一个, dispose不再调用
+                }
             }
         }
-    }
 
-    public static class CoroutineLockComponentSystem
-    {
         public static void RunNextCoroutine(this CoroutineLockComponent self, int coroutineLockType, long key, int level)
         {
             // 一个协程队列一帧处理超过100个,说明比较多了,打个warning,检查一下是否够正常
@@ -148,7 +154,7 @@ namespace ET
             return coroutineLock;
         }
 
-        public static void Notify(this CoroutineLockComponent self, int coroutineLockType, long key, int level)
+        private static void Notify(this CoroutineLockComponent self, int coroutineLockType, long key, int level)
         {
             CoroutineLockQueueType coroutineLockQueueType = self.list[coroutineLockType];
             if (!coroutineLockQueueType.TryGetValue(key, out CoroutineLockQueue queue))

+ 29 - 25
Unity/Codes/Model/Module/CoroutineLock/CoroutineLockQueue.cs

@@ -2,39 +2,48 @@
 
 namespace ET
 {
-    [ObjectSystem]
-    public class CoroutineLockQueueAwakeSystem: AwakeSystem<CoroutineLockQueue>
+    public struct CoroutineLockInfo
     {
-        public override void Awake(CoroutineLockQueue self)
-        {
-            self.queue.Clear();
-        }
+        public ETTask<CoroutineLock> Tcs;
+        public int Time;
     }
 
-    [ObjectSystem]
-    public class CoroutineLockQueueDestroySystem: DestroySystem<CoroutineLockQueue>
+    [FriendClass(typeof(CoroutineLockQueue))]
+    public static class CoroutineLockQueueSystem
     {
-        public override void Destroy(CoroutineLockQueue self)
+        [ObjectSystem]
+        public class CoroutineLockQueueAwakeSystem: AwakeSystem<CoroutineLockQueue>
         {
-            self.queue.Clear();
+            public override void Awake(CoroutineLockQueue self)
+            {
+                self.queue.Clear();
+            }
         }
-    }
 
-    public struct CoroutineLockInfo
-    {
-        public ETTask<CoroutineLock> Tcs;
-        public int Time;
+        [ObjectSystem]
+        public class CoroutineLockQueueDestroySystem: DestroySystem<CoroutineLockQueue>
+        {
+            public override void Destroy(CoroutineLockQueue self)
+            {
+                self.queue.Clear();
+            }
+        }
+        
+        public static void Add(this CoroutineLockQueue self, ETTask<CoroutineLock> tcs, int time)
+        {
+            self.queue.Enqueue(new CoroutineLockInfo(){Tcs = tcs, Time = time});
+        }
+        
+        public static CoroutineLockInfo Dequeue(this CoroutineLockQueue self)
+        {
+            return self.queue.Dequeue();
+        }
     }
     
     public class CoroutineLockQueue: Entity, IAwake, IDestroy
     {
         public Queue<CoroutineLockInfo> queue = new Queue<CoroutineLockInfo>();
 
-        public void Add(ETTask<CoroutineLock> tcs, int time)
-        {
-            this.queue.Enqueue(new CoroutineLockInfo(){Tcs = tcs, Time = time});
-        }
-
         public int Count
         {
             get
@@ -42,10 +51,5 @@ namespace ET
                 return this.queue.Count;
             }
         }
-
-        public CoroutineLockInfo Dequeue()
-        {
-            return this.queue.Dequeue();
-        }
     }
 }

+ 25 - 28
Unity/Codes/Model/Module/CoroutineLock/CoroutineLockQueueType.cs

@@ -1,52 +1,49 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
 
 namespace ET
 {
-    [ObjectSystem]
-    public class CoroutineLockQueueTypeAwakeSystem: AwakeSystem<CoroutineLockQueueType>
+    [FriendClass(typeof(CoroutineLockQueueType))]
+    public static class CoroutineLockQueueTypeSystem
     {
-        public override void Awake(CoroutineLockQueueType self)
+        [ObjectSystem]
+        public class CoroutineLockQueueTypeAwakeSystem: AwakeSystem<CoroutineLockQueueType>
         {
-            if (self.dictionary == null)
+            public override void Awake(CoroutineLockQueueType self)
             {
-                self.dictionary = new Dictionary<long, CoroutineLockQueue>();
             }
-
-            self.dictionary.Clear();
         }
-    }
 
-    [ObjectSystem]
-    public class CoroutineLockQueueTypeDestroySystem: DestroySystem<CoroutineLockQueueType>
-    {
-        public override void Destroy(CoroutineLockQueueType self)
+        [ObjectSystem]
+        public class CoroutineLockQueueTypeDestroySystem: DestroySystem<CoroutineLockQueueType>
         {
-            self.dictionary.Clear();
+            public override void Destroy(CoroutineLockQueueType self)
+            {
+                self.dictionary.Clear();
+            }
         }
-    }
-    
-    public class CoroutineLockQueueType: Entity, IAwake, IDestroy
-    {
-        public Dictionary<long, CoroutineLockQueue> dictionary;
-
-        public bool TryGetValue(long key, out CoroutineLockQueue value)
+        
+        public static bool TryGetValue(this CoroutineLockQueueType self, long key, out CoroutineLockQueue value)
         {
-            return this.dictionary.TryGetValue(key, out value);
+            return self.dictionary.TryGetValue(key, out value);
         }
 
-        public void Remove(long key)
+        public static void Remove(this CoroutineLockQueueType self, long key)
         {
-            if (this.dictionary.TryGetValue(key, out CoroutineLockQueue value))
+            if (self.dictionary.TryGetValue(key, out CoroutineLockQueue value))
             {
                 value.Dispose();
             }
-            this.dictionary.Remove(key);
+            self.dictionary.Remove(key);
         }
         
-        public void Add(long key, CoroutineLockQueue value)
+        public static void Add(this CoroutineLockQueueType self, long key, CoroutineLockQueue value)
         {
-            this.dictionary.Add(key, value);
+            self.dictionary.Add(key, value);
         }
     }
+    
+    public class CoroutineLockQueueType: Entity, IAwake, IDestroy
+    {
+        public Dictionary<long, CoroutineLockQueue> dictionary = new Dictionary<long, CoroutineLockQueue>();
+    }
 }

+ 73 - 73
Unity/Codes/Model/Module/Message/OpcodeTypeComponent.cs

@@ -3,110 +3,110 @@ using System.Collections.Generic;
 
 namespace ET
 {
-    [ObjectSystem]
-    public class OpcodeTypeComponentAwakeSystem: AwakeSystem<OpcodeTypeComponent>
+    [FriendClass(typeof(OpcodeTypeComponent))]
+    public static class OpcodeTypeComponentSystem
     {
-        public override void Awake(OpcodeTypeComponent self)
+        [ObjectSystem]
+        public class OpcodeTypeComponentAwakeSystem: AwakeSystem<OpcodeTypeComponent>
         {
-            OpcodeTypeComponent.Instance = self;
-            self.Awake();
-        }
-    }
-
-    [ObjectSystem]
-    public class OpcodeTypeComponentDestroySystem: DestroySystem<OpcodeTypeComponent>
-    {
-        public override void Destroy(OpcodeTypeComponent self)
-        {
-            OpcodeTypeComponent.Instance = null;
-        }
-    }
-
-    public class OpcodeTypeComponent: Entity, IAwake, IDestroy
-    {
-        public static OpcodeTypeComponent Instance;
-        
-        private HashSet<ushort> outrActorMessage = new HashSet<ushort>();
-        
-        private readonly Dictionary<ushort, Type> opcodeTypes = new Dictionary<ushort, Type>();
-        private readonly Dictionary<Type, ushort> typeOpcodes = new Dictionary<Type, ushort>();
-        
-        private readonly Dictionary<Type, Type> requestResponse = new Dictionary<Type, Type>();
-        
-        public void Awake()
-        {
-            this.opcodeTypes.Clear();
-            this.typeOpcodes.Clear();
-            this.requestResponse.Clear();
-
-            HashSet<Type> types = Game.EventSystem.GetTypes(typeof (MessageAttribute));
-            foreach (Type type in types)
+            public override void Awake(OpcodeTypeComponent self)
             {
-                object[] attrs = type.GetCustomAttributes(typeof (MessageAttribute), false);
-                if (attrs.Length == 0)
-                {
-                    continue;
-                }
-
-                MessageAttribute messageAttribute = attrs[0] as MessageAttribute;
-                if (messageAttribute == null)
-                {
-                    continue;
-                }
+                OpcodeTypeComponent.Instance = self;
                 
+                self.opcodeTypes.Clear();
+                self.typeOpcodes.Clear();
+                self.requestResponse.Clear();
 
-                this.opcodeTypes.Add(messageAttribute.Opcode, type);
-                this.typeOpcodes.Add(type, messageAttribute.Opcode);
-
-                if (OpcodeHelper.IsOuterMessage(messageAttribute.Opcode) && typeof (IActorMessage).IsAssignableFrom(type))
-                {
-                    this.outrActorMessage.Add(messageAttribute.Opcode);
-                }
-                
-                // 检查request response
-                if (typeof (IRequest).IsAssignableFrom(type))
+                HashSet<Type> types = Game.EventSystem.GetTypes(typeof (MessageAttribute));
+                foreach (Type type in types)
                 {
-                    if (typeof (IActorLocationMessage).IsAssignableFrom(type))
+                    object[] attrs = type.GetCustomAttributes(typeof (MessageAttribute), false);
+                    if (attrs.Length == 0)
                     {
-                        this.requestResponse.Add(type, typeof(ActorResponse));
                         continue;
                     }
-                    
-                    attrs = type.GetCustomAttributes(typeof (ResponseTypeAttribute), false);
-                    if (attrs.Length == 0)
+
+                    MessageAttribute messageAttribute = attrs[0] as MessageAttribute;
+                    if (messageAttribute == null)
                     {
-                        Log.Error($"not found responseType: {type}");
                         continue;
                     }
+                
+
+                    self.opcodeTypes.Add(messageAttribute.Opcode, type);
+                    self.typeOpcodes.Add(type, messageAttribute.Opcode);
 
-                    ResponseTypeAttribute responseTypeAttribute = attrs[0] as ResponseTypeAttribute;
-                    this.requestResponse.Add(type, Game.EventSystem.GetType($"ET.{responseTypeAttribute.Type}"));
+                    if (OpcodeHelper.IsOuterMessage(messageAttribute.Opcode) && typeof (IActorMessage).IsAssignableFrom(type))
+                    {
+                        self.outrActorMessage.Add(messageAttribute.Opcode);
+                    }
+                
+                    // 检查request response
+                    if (typeof (IRequest).IsAssignableFrom(type))
+                    {
+                        if (typeof (IActorLocationMessage).IsAssignableFrom(type))
+                        {
+                            self.requestResponse.Add(type, typeof(ActorResponse));
+                            continue;
+                        }
+                    
+                        attrs = type.GetCustomAttributes(typeof (ResponseTypeAttribute), false);
+                        if (attrs.Length == 0)
+                        {
+                            Log.Error($"not found responseType: {type}");
+                            continue;
+                        }
+
+                        ResponseTypeAttribute responseTypeAttribute = attrs[0] as ResponseTypeAttribute;
+                        self.requestResponse.Add(type, Game.EventSystem.GetType($"ET.{responseTypeAttribute.Type}"));
+                    }
                 }
             }
         }
 
-        public bool IsOutrActorMessage(ushort opcode)
+        [ObjectSystem]
+        public class OpcodeTypeComponentDestroySystem: DestroySystem<OpcodeTypeComponent>
         {
-            return this.outrActorMessage.Contains(opcode);
+            public override void Destroy(OpcodeTypeComponent self)
+            {
+                OpcodeTypeComponent.Instance = null;
+            }
         }
 
-        public ushort GetOpcode(Type type)
+        public static bool IsOutrActorMessage(this OpcodeTypeComponent self, ushort opcode)
         {
-            return this.typeOpcodes[type];
+            return self.outrActorMessage.Contains(opcode);
         }
 
-        public Type GetType(ushort opcode)
+        public static ushort GetOpcode(this OpcodeTypeComponent self, Type type)
         {
-            return this.opcodeTypes[opcode];
+            return self.typeOpcodes[type];
         }
 
-        public Type GetResponseType(Type request)
+        public static Type GetType(this OpcodeTypeComponent self, ushort opcode)
         {
-            if (!this.requestResponse.TryGetValue(request, out Type response))
+            return self.opcodeTypes[opcode];
+        }
+
+        public static Type GetResponseType(this OpcodeTypeComponent self, Type request)
+        {
+            if (!self.requestResponse.TryGetValue(request, out Type response))
             {
                 throw new Exception($"not found response type, request type: {request.GetType().Name}");
             }
             return response;
         }
     }
+
+    public class OpcodeTypeComponent: Entity, IAwake, IDestroy
+    {
+        public static OpcodeTypeComponent Instance;
+        
+        public HashSet<ushort> outrActorMessage = new HashSet<ushort>();
+        
+        public readonly Dictionary<ushort, Type> opcodeTypes = new Dictionary<ushort, Type>();
+        public readonly Dictionary<Type, ushort> typeOpcodes = new Dictionary<Type, ushort>();
+        
+        public readonly Dictionary<Type, Type> requestResponse = new Dictionary<Type, Type>();
+    }
 }

+ 94 - 101
Unity/Codes/Model/Module/Message/Session.cs

@@ -6,109 +6,65 @@ using System.Net;
 
 namespace ET
 {
-    [ObjectSystem]
-    public class SessionAwakeSystem: AwakeSystem<Session, AService>
+    public readonly struct RpcInfo
     {
-        public override void Awake(Session self, AService aService)
+        public readonly IRequest Request;
+        public readonly ETTask<IResponse> Tcs;
+
+        public RpcInfo(IRequest request)
         {
-            self.Awake(aService);
+            this.Request = request;
+            this.Tcs = ETTask<IResponse>.Create(true);
         }
     }
-
-    public sealed class Session: Entity, IAwake<AService>
+    
+    [FriendClass(typeof(Session))]
+    public static class SessionSystem
     {
-        private readonly struct RpcInfo
+        [ObjectSystem]
+        public class SessionAwakeSystem: AwakeSystem<Session, AService>
         {
-            public readonly IRequest Request;
-            public readonly ETTask<IResponse> Tcs;
-
-            public RpcInfo(IRequest request)
+            public override void Awake(Session self, AService aService)
             {
-                this.Request = request;
-                this.Tcs = ETTask<IResponse>.Create(true);
-            }
-        }
-
-        public AService AService;
-        
-        private static int RpcId
-        {
-            get;
-            set;
-        }
-
-        private readonly Dictionary<int, RpcInfo> requestCallbacks = new Dictionary<int, RpcInfo>();
-        
-        public long LastRecvTime
-        {
-            get;
-            set;
-        }
-
-        public long LastSendTime
-        {
-            get;
-            set;
-        }
-
-        public int Error
-        {
-            get;
-            set;
-        }
-
-        public void Awake(AService aService)
-        {
-            this.AService = aService;
-            long timeNow = TimeHelper.ClientNow();
-            this.LastRecvTime = timeNow;
-            this.LastSendTime = timeNow;
+                self.AService = aService;
+                long timeNow = TimeHelper.ClientNow();
+                self.LastRecvTime = timeNow;
+                self.LastSendTime = timeNow;
 
-            this.requestCallbacks.Clear();
+                self.requestCallbacks.Clear();
             
-            Log.Info($"session create: zone: {this.DomainZone()} id: {this.Id} {timeNow} ");
+                Log.Info($"session create: zone: {self.DomainZone()} id: {self.Id} {timeNow} ");
+            }
         }
-
-        public override void Dispose()
+        
+        [ObjectSystem]
+        public class SessionDestroySystem: DestroySystem<Session>
         {
-            if (this.IsDisposed)
+            public override void Destroy(Session self)
             {
-                return;
-            }
-
-            int zone = this.DomainZone();
-            long id = this.Id;
-
-            base.Dispose();
+                self.AService.RemoveChannel(self.Id);
+            
+                foreach (RpcInfo responseCallback in self.requestCallbacks.Values.ToArray())
+                {
+                    responseCallback.Tcs.SetException(new RpcException(self.Error, $"session dispose: {self.Id} {self.RemoteAddress}"));
+                }
 
-            this.AService.RemoveChannel(this.Id);
+                Log.Info($"session dispose: {self.RemoteAddress} id: {self.Id} ErrorCode: {self.Error}, please see ErrorCode.cs! {TimeHelper.ClientNow()}");
             
-            foreach (RpcInfo responseCallback in this.requestCallbacks.Values.ToArray())
-            {
-                responseCallback.Tcs.SetException(new RpcException(this.Error, $"session dispose: {id} {this.RemoteAddress}"));
+                self.requestCallbacks.Clear();
             }
-
-            Log.Info($"session dispose: {this.RemoteAddress} zone: {zone} id: {id} ErrorCode: {this.Error}, please see ErrorCode.cs! {TimeHelper.ClientNow()}");
-
-            this.requestCallbacks.Clear();
         }
-
-        public IPEndPoint RemoteAddress
-        {
-            get;
-            set;
-        }
-
-        public void OnRead(ushort opcode, IResponse response)
+        
+        public static void OnRead(this Session self, ushort opcode, IResponse response)
         {
-            OpcodeHelper.LogMsg(this.DomainZone(), opcode, response);
+            OpcodeHelper.LogMsg(self.DomainZone(), opcode, response);
             
-            if (!this.requestCallbacks.TryGetValue(response.RpcId, out var action))
+            if (!self.requestCallbacks.TryGetValue(response.RpcId, out var action))
             {
                 return;
             }
 
-            this.requestCallbacks.Remove(response.RpcId);
+            self.requestCallbacks.Remove(response.RpcId);
             if (ErrorCore.IsRpcNeedThrowException(response.Error))
             {
                 action.Tcs.SetException(new Exception($"Rpc error, request: {action.Request} response: {response}"));
@@ -117,23 +73,23 @@ namespace ET
             action.Tcs.SetResult(response);
         }
         
-        public async ETTask<IResponse> Call(IRequest request, ETCancellationToken cancellationToken)
+        public static async ETTask<IResponse> Call(this Session self, IRequest request, ETCancellationToken cancellationToken)
         {
-            int rpcId = ++RpcId;
+            int rpcId = ++Session.RpcId;
             RpcInfo rpcInfo = new RpcInfo(request);
-            this.requestCallbacks[rpcId] = rpcInfo;
+            self.requestCallbacks[rpcId] = rpcInfo;
             request.RpcId = rpcId;
 
-            this.Send(request);
+            self.Send(request);
             
             void CancelAction()
             {
-                if (!this.requestCallbacks.TryGetValue(rpcId, out RpcInfo action))
+                if (!self.requestCallbacks.TryGetValue(rpcId, out RpcInfo action))
                 {
                     return;
                 }
 
-                this.requestCallbacks.Remove(rpcId);
+                self.requestCallbacks.Remove(rpcId);
                 Type responseType = OpcodeTypeComponent.Instance.GetResponseType(action.Request.GetType());
                 IResponse response = (IResponse) Activator.CreateInstance(responseType);
                 response.Error = ErrorCore.ERR_Cancel;
@@ -153,37 +109,74 @@ namespace ET
             return ret;
         }
 
-        public async ETTask<IResponse> Call(IRequest request)
+        public static async ETTask<IResponse> Call(this Session self, IRequest request)
         {
-            int rpcId = ++RpcId;
+            int rpcId = ++Session.RpcId;
             RpcInfo rpcInfo = new RpcInfo(request);
-            this.requestCallbacks[rpcId] = rpcInfo;
+            self.requestCallbacks[rpcId] = rpcInfo;
             request.RpcId = rpcId;
-            this.Send(request);
+            self.Send(request);
             return await rpcInfo.Tcs;
         }
 
-        public void Reply(IResponse message)
+        public static void Reply(this Session self, IResponse message)
         {
-            this.Send(0, message);
+            self.Send(0, message);
         }
 
-        public void Send(IMessage message)
+        public static void Send(this Session self, IMessage message)
         {
-            this.Send(0, message);
+            self.Send(0, message);
         }
         
-        public void Send(long actorId, IMessage message)
+        public static void Send(this Session self, long actorId, IMessage message)
         {
             (ushort opcode, MemoryStream stream) = MessageSerializeHelper.MessageToStream(message);
-            OpcodeHelper.LogMsg(this.DomainZone(), opcode, message);
-            this.Send(actorId, stream);
+            OpcodeHelper.LogMsg(self.DomainZone(), opcode, message);
+            self.Send(actorId, stream);
+        }
+        
+        public static void Send(this Session self, long actorId, MemoryStream memoryStream)
+        {
+            self.LastSendTime = TimeHelper.ClientNow();
+            self.AService.SendStream(self.Id, actorId, memoryStream);
+        }
+    }
+
+    public sealed class Session: Entity, IAwake<AService>, IDestroy
+    {
+        public AService AService;
+        
+        public static int RpcId
+        {
+            get;
+            set;
         }
+
+        public readonly Dictionary<int, RpcInfo> requestCallbacks = new Dictionary<int, RpcInfo>();
         
-        public void Send(long actorId, MemoryStream memoryStream)
+        public long LastRecvTime
+        {
+            get;
+            set;
+        }
+
+        public long LastSendTime
+        {
+            get;
+            set;
+        }
+
+        public int Error
         {
-            this.LastSendTime = TimeHelper.ClientNow();
-            this.AService.SendStream(this.Id, actorId, memoryStream);
+            get;
+            set;
+        }
+
+        public IPEndPoint RemoteAddress
+        {
+            get;
+            set;
         }
     }
 }

+ 0 - 23
Unity/Codes/Model/Module/Message/SessionCallbackComponent.cs

@@ -1,23 +0,0 @@
-using System;
-using System.IO;
-
-namespace ET
-{
-    public class SessionCallbackComponent: Entity
-    {
-        public Action<Session, ushort, MemoryStream> MessageCallback;
-        public Action<Session> DisposeCallback;
-
-        public override void Dispose()
-        {
-            if (this.IsDisposed)
-            {
-                return;
-            }
-
-            base.Dispose();
-
-            this.DisposeCallback?.Invoke(this.GetParent<Session>());
-        }
-    }
-}

+ 46 - 62
Unity/Codes/Model/Module/Numeric/NumericComponent.cs

@@ -1,4 +1,5 @@
 using System.Collections.Generic;
+using ET.EventType;
 using MongoDB.Bson.Serialization.Attributes;
 using MongoDB.Bson.Serialization.Options;
 
@@ -14,111 +15,75 @@ namespace ET
 			public long New;
 		}
 	}
-	
-	[ObjectSystem]
-	public class NumericComponentAwakeSystem : AwakeSystem<NumericComponent>
-	{
-		public override void Awake(NumericComponent self)
-		{
-			self.Awake();
-		}
-	}
 
-	public class NumericComponent: Entity, IAwake, ITransfer
+	[FriendClass(typeof(NumericComponent))]
+	public static class NumericComponentSystem
 	{
-		[BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)]
-		public Dictionary<int, long> NumericDic = new Dictionary<int, long>();
-
-		public void Awake()
-		{
-			// 这里初始化base值
-		}
-
-		public float GetAsFloat(int numericType)
+		public static float GetAsFloat(this NumericComponent self, int numericType)
 		{
-			return (float)GetByKey(numericType) / 10000;
+			return (float)self.GetByKey(numericType) / 10000;
 		}
 
-		public int GetAsInt(int numericType)
+		public static int GetAsInt(this NumericComponent self, int numericType)
 		{
-			return (int)GetByKey(numericType);
+			return (int)self.GetByKey(numericType);
 		}
 		
-		public long GetAsLong(int numericType)
+		public static long GetAsLong(this NumericComponent self, int numericType)
 		{
-			return GetByKey(numericType);
+			return self.GetByKey(numericType);
 		}
 
-		public void Set(int nt, float value)
+		public static void Set(this NumericComponent self, int nt, float value)
 		{
-			this[nt] = (int) (value * 10000);
+			self[nt] = (int) (value * 10000);
 		}
 
-		public void Set(int nt, int value)
+		public static void Set(this NumericComponent self, int nt, int value)
 		{
-			this[nt] = value;
+			self[nt] = value;
 		}
 		
-		public void Set(int nt, long value)
+		public static void Set(this NumericComponent self, int nt, long value)
 		{
-			this[nt] = value;
+			self[nt] = value;
 		}
 
-		public void SetNoEvent(int numericType, long value)
-		{
-			this.Insert(numericType,value,false);
-		}
-		
-		
-		public long this[int numericType]
+		public static void SetNoEvent(this NumericComponent self, int numericType, long value)
 		{
-			get
-			{
-				return this.GetByKey(numericType);
-			}
-			set
-			{
-				
-				this.Insert(numericType,value);
-			}
+			self.Insert(numericType,value,false);
 		}
 		
-		private void Insert(int numericType, long value,bool isPublicEvent = true)
+		public static void Insert(this NumericComponent self, int numericType, long value,bool isPublicEvent = true)
 		{
-			long oldValue = this.GetByKey(numericType);
+			long oldValue = self.GetByKey(numericType);
 			if (oldValue == value)
 			{
 				return;
 			}
 
-			NumericDic[numericType] = value;
+			self.NumericDic[numericType] = value;
 
 			if (numericType >= NumericType.Max)
 			{
-				Update(numericType,isPublicEvent);
+				self.Update(numericType,isPublicEvent);
 				return;
 			}
 
 			if (isPublicEvent)
 			{
-				Game.EventSystem.Publish(new EventType.NumbericChange()
-				{
-					Parent = this.Parent, 
-					NumericType = numericType,
-					Old = oldValue,
-					New = value
-				});
+				Game.EventSystem.Publish(new NumbericChange() {New = value, Old = oldValue, Parent = self.Parent, NumericType = numericType});
 			}
 		}
 		
-		private long GetByKey(int key)
+		public static long GetByKey(this NumericComponent self, int key)
 		{
 			long value = 0;
-			this.NumericDic.TryGetValue(key, out value);
+			self.NumericDic.TryGetValue(key, out value);
 			return value;
 		}
 
-		public void Update(int numericType,bool isPublicEvent)
+		public static void Update(this NumericComponent self, int numericType,bool isPublicEvent)
 		{
 			int final = (int) numericType / 10;
 			int bas = final * 10 + 1; 
@@ -129,8 +94,27 @@ namespace ET
 
 			// 一个数值可能会多种情况影响,比如速度,加个buff可能增加速度绝对值100,也有些buff增加10%速度,所以一个值可以由5个值进行控制其最终结果
 			// final = (((base + add) * (100 + pct) / 100) + finalAdd) * (100 + finalPct) / 100;
-			long result = (long)(((this.GetByKey(bas) + this.GetByKey(add)) * (100 + this.GetAsFloat(pct)) / 100f + this.GetByKey(finalAdd)) * (100 + this.GetAsFloat(finalPct)) / 100f);
-			this.Insert(final,result,isPublicEvent);
+			long result = (long)(((self.GetByKey(bas) + self.GetByKey(add)) * (100 + self.GetAsFloat(pct)) / 100f + self.GetByKey(finalAdd)) * (100 + self.GetAsFloat(finalPct)) / 100f);
+			self.Insert(final,result,isPublicEvent);
+		}
+	}
+	
+
+	public class NumericComponent: Entity, IAwake, ITransfer
+	{
+		[BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)]
+		public Dictionary<int, long> NumericDic = new Dictionary<int, long>();
+
+		public long this[int numericType]
+		{
+			get
+			{
+				return this.GetByKey(numericType);
+			}
+			set
+			{
+				this.Insert(numericType,value);
+			}
 		}
 	}
 }

+ 62 - 62
Unity/Codes/Model/Module/Numeric/NumericWatcherComponent.cs

@@ -3,72 +3,72 @@ using System.Collections.Generic;
 
 namespace ET
 {
-	[ObjectSystem]
-	public class NumericWatcherComponentAwakeSystem : AwakeSystem<NumericWatcherComponent>
-	{
-		public override void Awake(NumericWatcherComponent self)
-		{
-			NumericWatcherComponent.Instance = self;
-			self.Awake();
-		}
-	}
+    [FriendClass(typeof(NumericWatcherComponent))]
+    public static class NumericWatcherComponentSystem
+    {
+        [ObjectSystem]
+        public class NumericWatcherComponentAwakeSystem : AwakeSystem<NumericWatcherComponent>
+        {
+            public override void Awake(NumericWatcherComponent self)
+            {
+                NumericWatcherComponent.Instance = self;
+                self.Init();
+            }
+        }
 
 	
-	public class NumericWatcherComponentLoadSystem : LoadSystem<NumericWatcherComponent>
-	{
-		public override void Load(NumericWatcherComponent self)
-		{
-			self.Load();
-		}
-	}
+        public class NumericWatcherComponentLoadSystem : LoadSystem<NumericWatcherComponent>
+        {
+            public override void Load(NumericWatcherComponent self)
+            {
+                self.Init();
+            }
+        }
 
-	/// <summary>
-	/// 监视数值变化组件,分发监听
-	/// </summary>
-	public class NumericWatcherComponent : Entity, IAwake, ILoad
-	{
-		public static NumericWatcherComponent Instance { get; set; }
-		
-		private Dictionary<int, List<INumericWatcher>> allWatchers;
-
-		public void Awake()
-		{
-			this.Load();
-		}
+        private static void Init(this NumericWatcherComponent self)
+        {
+            self.allWatchers = new Dictionary<int, List<INumericWatcher>>();
 
-		public void Load()
-		{
-			this.allWatchers = new Dictionary<int, List<INumericWatcher>>();
+            HashSet<Type> types = Game.EventSystem.GetTypes(typeof(NumericWatcherAttribute));
+            foreach (Type type in types)
+            {
+                object[] attrs = type.GetCustomAttributes(typeof(NumericWatcherAttribute), false);
 
-			HashSet<Type> types = Game.EventSystem.GetTypes(typeof(NumericWatcherAttribute));
-			foreach (Type type in types)
-			{
-				object[] attrs = type.GetCustomAttributes(typeof(NumericWatcherAttribute), false);
+                foreach (object attr in attrs)
+                {
+                    NumericWatcherAttribute numericWatcherAttribute = (NumericWatcherAttribute)attr;
+                    INumericWatcher obj = (INumericWatcher)Activator.CreateInstance(type);
+                    if (!self.allWatchers.ContainsKey(numericWatcherAttribute.NumericType))
+                    {
+                        self.allWatchers.Add(numericWatcherAttribute.NumericType, new List<INumericWatcher>());
+                    }
+                    self.allWatchers[numericWatcherAttribute.NumericType].Add(obj);
+                }
+            }
+        }
 
-				foreach (object attr in attrs)
-				{
-					NumericWatcherAttribute numericWatcherAttribute = (NumericWatcherAttribute)attr;
-					INumericWatcher obj = (INumericWatcher)Activator.CreateInstance(type);
-					if (!this.allWatchers.ContainsKey(numericWatcherAttribute.NumericType))
-					{
-						this.allWatchers.Add(numericWatcherAttribute.NumericType, new List<INumericWatcher>());
-					}
-					this.allWatchers[numericWatcherAttribute.NumericType].Add(obj);
-				}
-			}
-		}
-
-		public void Run(EventType.NumbericChange args)
-		{
-			List<INumericWatcher> list;
-			if (!this.allWatchers.TryGetValue(args.NumericType, out list))
-			{
-				return;
-			}
-			foreach (INumericWatcher numericWatcher in list)
-			{
-				numericWatcher.Run(args);
-			}
-		}
-	}
+        public static void Run(this NumericWatcherComponent self, EventType.NumbericChange args)
+        {
+            List<INumericWatcher> list;
+            if (!self.allWatchers.TryGetValue(args.NumericType, out list))
+            {
+                return;
+            }
+            foreach (INumericWatcher numericWatcher in list)
+            {
+                numericWatcher.Run(args);
+            }
+        }
+    }
+    
+    
+    /// <summary>
+    /// 监视数值变化组件,分发监听
+    /// </summary>
+    public class NumericWatcherComponent : Entity, IAwake, ILoad
+    {
+        public static NumericWatcherComponent Instance { get; set; }
+		
+        public Dictionary<int, List<INumericWatcher>> allWatchers;
+    }
 }

+ 0 - 96
Unity/Codes/Model/Module/UnityWebRequest/UnityWebRequestAsync.cs

@@ -1,96 +0,0 @@
-using System;
-using UnityEngine.Networking;
-
-namespace ET
-{
-	
-	public class UnityWebRequestUpdateSystem : UpdateSystem<UnityWebRequestAsync>
-	{
-		public override void Update(UnityWebRequestAsync self)
-		{
-			self.Update();
-		}
-	}
-	
-	public class UnityWebRequestAsync : Entity, IUpdate
-	{
-		public static AcceptAllCertificate certificateHandler = new AcceptAllCertificate();
-		
-		public UnityWebRequest Request;
-
-		public bool isCancel;
-
-		public ETTask tcs;
-		
-		public override void Dispose()
-		{
-			if (this.IsDisposed)
-			{
-				return;
-			}
-
-			base.Dispose();
-
-			this.Request?.Dispose();
-			this.Request = null;
-			this.isCancel = false;
-		}
-
-		public float Progress
-		{
-			get
-			{
-				if (this.Request == null)
-				{
-					return 0;
-				}
-				return this.Request.downloadProgress;
-			}
-		}
-
-		public ulong ByteDownloaded
-		{
-			get
-			{
-				if (this.Request == null)
-				{
-					return 0;
-				}
-				return this.Request.downloadedBytes;
-			}
-		}
-
-		public void Update()
-		{
-			if (this.isCancel)
-			{
-				this.tcs.SetException(new Exception($"request error: {this.Request.error}"));
-				return;
-			}
-			
-			if (!this.Request.isDone)
-			{
-				return;
-			}
-			if (!string.IsNullOrEmpty(this.Request.error))
-			{
-				this.tcs.SetException(new Exception($"request error: {this.Request.error}"));
-				return;
-			}
-
-			this.tcs.SetResult();
-		}
-
-		public async ETTask DownloadAsync(string url)
-		{
-			this.tcs = ETTask.Create(true);
-			
-			url = url.Replace(" ", "%20");
-			this.Request = UnityWebRequest.Get(url);
-			this.Request.certificateHandler = certificateHandler;
-			this.Request.SendWebRequest();
-			
-			await this.tcs;
-		}
-	}
-}

+ 0 - 352
Unity/Codes/Model/Module/UnityWebRequest/UnityWebRequestRenewalAsync.cs

@@ -1,352 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using UnityEngine;
-using UnityEngine.Networking;
-
-namespace ET
-{
-    public class UnityWebRequestRenewalUpdateSystem: UpdateSystem<UnityWebRequestRenewalAsync>
-    {
-        public override void Update(UnityWebRequestRenewalAsync self)
-        {
-            self.Update();
-        }
-    }
-
-    /// <summary>
-    /// 断点续传实现
-    /// </summary>
-    public class UnityWebRequestRenewalAsync: Entity, IUpdate
-    {
-        public static AcceptAllCertificate certificateHandler = new AcceptAllCertificate();
-
-        public UnityWebRequest headRequest;
-
-        public bool isCancel;
-
-        public ETTask tcs;
-
-        //请求资源类型
-        private class RequestType
-        {
-            public const int None = 0; //未开始
-            public const int Head = 1; //文件头
-            public const int Data = 2; //文件数据
-        }
-
-        //当前请求资源类型
-        private int requestType = RequestType.None;
-
-        //多任务同时请求
-        private readonly List<UnityWebRequest> dataRequests = new List<UnityWebRequest>();
-
-        //当前下载的文件流 边下边存文件流
-        private FileStream fileStream;
-
-        //资源地址
-        private string Url;
-
-        //每个下载包长度
-        private int packageLength = 1000000; //1M
-
-        //同时开启任务最大个数
-        private int maxCount = 20;
-
-        //已经写入文件的大小
-        private long byteWrites;
-
-        //文件总大小
-        private long totalBytes;
-
-        //当前请求的位置
-        private long downloadIndex;
-
-        //文件下载是否出错
-        private string dataError
-        {
-            get
-            {
-                foreach (UnityWebRequest webRequest in this.dataRequests)
-                {
-                    if (!string.IsNullOrEmpty(webRequest.error))
-                    {
-                        return webRequest.error;
-                    }
-                }
-
-                return "";
-            }
-        }
-
-        //批量开启任务下载
-        private void DownloadPackages()
-        {
-            if (dataRequests.Count >= maxCount || this.downloadIndex == totalBytes - 1)
-            {
-                return;
-            }
-
-            //开启一个下载任务
-            void DownloadPackage(long start, long end)
-            {
-                this.downloadIndex = end;
-                Log.Debug($"Request Data ({start}~{end}):{Url}");
-                UnityWebRequest request = UnityWebRequest.Get(Url);
-                dataRequests.Add(request);
-                request.certificateHandler = certificateHandler;
-                request.SetRequestHeader("Range", $"bytes={start}-{end}");
-                request.SendWebRequest();
-            }
-
-            //开启批量下载
-            for (int i = dataRequests.Count; i < maxCount; i++)
-            {
-                long start = this.byteWrites + i * packageLength;
-                long end = this.byteWrites + (i + 1) * packageLength - 1;
-                if (end > this.totalBytes)
-                {
-                    end = this.totalBytes - 1;
-                }
-
-                DownloadPackage(start, end);
-                if (end == this.totalBytes - 1)
-                {
-                    break;
-                }
-            }
-        }
-
-        //一次批量下载完成后写文件
-        private void WritePackages()
-        {
-            //写入单个包
-            void WritePackage(UnityWebRequest webRequest)
-            {
-                byte[] buff = webRequest.downloadHandler.data;
-                if (buff != null && buff.Length > 0)
-                {
-                    this.fileStream.Write(buff, 0, buff.Length);
-                    this.byteWrites += buff.Length;
-                }
-
-                Log.Debug($"write file Length:{byteWrites}");
-            }
-
-            //从第一个开始顺序写入
-            while (this.dataRequests.Count > 0 && dataRequests[0].isDone)
-            {
-                UnityWebRequest first = dataRequests[0];
-                dataRequests.RemoveAt(0);
-                WritePackage(first);
-                first.Dispose();
-            }
-        }
-
-        //更新文件体下载
-        private void UpdatePackages()
-        {
-            if (this.isCancel)
-            {
-                this.tcs.SetException(new Exception($"request data error: {dataError}"));
-                return;
-            }
-
-            if (!string.IsNullOrEmpty(dataError))
-            {
-                this.tcs.SetException(new Exception($"request data error: {dataError}"));
-                return;
-            }
-
-            this.WritePackages();
-            if (this.byteWrites == this.totalBytes)
-            {
-                this.tcs.SetResult();
-            }
-            else
-            {
-                this.DownloadPackages();
-            }
-        }
-
-        //更新文件头下载
-        private void UpdateHead()
-        {
-            if (this.isCancel)
-            {
-                this.tcs.SetException(new Exception($"request error: {this.headRequest.error}"));
-                return;
-            }
-
-            if (!this.headRequest.isDone)
-            {
-                return;
-            }
-
-            if (!string.IsNullOrEmpty(this.headRequest.error))
-            {
-                this.tcs.SetException(new Exception($"request error: {this.headRequest.error}"));
-                return;
-            }
-
-            this.tcs.SetResult();
-        }
-
-        //检测是不是同一个文件
-        private bool CheckSameFile(string modifiedTime)
-        {
-            string cacheValue = PlayerPrefs.GetString(Url);
-            string currentValue = this.totalBytes + "|" + modifiedTime;
-            if (cacheValue == currentValue)
-            {
-                return true;
-            }
-
-            PlayerPrefs.SetString(Url, currentValue);
-            PlayerPrefs.Save();
-            Log.Debug($"断点续传下载一个新的文件:{Url} cacheValue:{cacheValue} currentValue:{currentValue}");
-            return false;
-        }
-
-        /// <summary>
-        /// 断点续传入口
-        /// </summary>
-        /// <param name="url">文件下载地址</param>
-        /// <param name="filePath">文件写入路径</param>
-        /// <param name="packageLength">单个任务包体字节大小</param>
-        /// <param name="maxCount">同时开启最大任务个数</param>
-        /// <returns></returns>
-        public async ETTask DownloadAsync(string url, string filePath, int packageLength = 1000000, int maxCount = 20)
-        {
-            try
-            {
-                url = url.Replace(" ", "%20");
-                this.Url = url;
-                this.packageLength = packageLength;
-                this.maxCount = maxCount;
-                Log.Debug("Web Request:" + url);
-
-                #region Download File Header
-
-                this.requestType = RequestType.Head;
-                //下载文件头
-                Log.Debug($"Request Head: {Url}");
-                this.tcs = ETTask.Create(true);
-                this.headRequest = UnityWebRequest.Head(Url);
-                this.headRequest.SendWebRequest();
-                await this.tcs;
-                this.totalBytes = long.Parse(this.headRequest.GetResponseHeader("Content-Length"));
-                string modifiedTime = this.headRequest.GetResponseHeader("Last-Modified");
-                Log.Debug($"totalBytes: {this.totalBytes}");
-                this.headRequest?.Dispose();
-                this.headRequest = null;
-
-                #endregion
-
-                #region Check Local File
-
-                //打开或创建
-                fileStream = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write);
-                //获取已下载长度
-                this.byteWrites = fileStream.Length;
-                //通过本地缓存的服务器文件修改时间和文件总长度检测服务器是否是同一个文件 不是同一个从头开始写入
-                if (!CheckSameFile(modifiedTime))
-                {
-                    this.byteWrites = 0;
-                }
-
-                Log.Debug($"byteWrites: {this.byteWrites}");
-                if (this.byteWrites == this.totalBytes)
-                {
-                    Log.Debug("已经下载完成2");
-                    return;
-                }
-
-                //设置开始写入位置
-                fileStream.Seek(this.byteWrites, SeekOrigin.Begin);
-
-                #endregion
-
-                #region Download File Data
-
-                //下载文件数据
-                requestType = RequestType.Data;
-                Log.Debug($"Request Data: {Url}");
-                this.tcs = ETTask.Create(true);
-                this.DownloadPackages();
-                await this.tcs;
-
-                #endregion
-            }
-            catch (Exception e)
-            {
-                Log.Error($"下载:{Url} Exception:{e}");
-                throw;
-            }
-        }
-
-        //下载进度
-        public float Progress
-        {
-            get
-            {
-                if (this.totalBytes == 0)
-                {
-                    return 0;
-                }
-
-                return (float) ((this.byteWrites + ByteDownloaded) / (double) this.totalBytes);
-            }
-        }
-
-        //当前任务已经下载的长度
-        public long ByteDownloaded
-        {
-            get
-            {
-                long length = 0;
-                foreach (UnityWebRequest dataRequest in this.dataRequests)
-                {
-                    length += dataRequest.downloadHandler.data.Length;
-                }
-
-                return length;
-            }
-        }
-
-        public void Update()
-        {
-            if (this.requestType == RequestType.Head)
-            {
-                this.UpdateHead();
-            }
-
-            if (this.requestType == RequestType.Data)
-            {
-                this.UpdatePackages();
-            }
-        }
-
-        public override void Dispose()
-        {
-            if (this.IsDisposed)
-            {
-                return;
-            }
-
-            base.Dispose();
-            headRequest?.Dispose();
-            headRequest = null;
-            foreach (UnityWebRequest dataRequest in this.dataRequests)
-            {
-                dataRequest.Dispose();
-            }
-
-            dataRequests.Clear();
-            this.fileStream?.Close();
-            this.fileStream?.Dispose();
-            this.fileStream = null;
-            this.isCancel = false;
-        }
-    }
-}

+ 137 - 131
Unity/Codes/ModelView/Client/Resource/ResourcesComponent.cs

@@ -7,29 +7,43 @@ using UnityEngine;
 
 namespace ET
 {
-    [ObjectSystem]
-    public class ABInfoAwakeSystem: AwakeSystem<ABInfo, string, AssetBundle>
+    [FriendClass(typeof(ABInfo))]
+    public static class ABInfoSystem
     {
-        public override void Awake(ABInfo self, string abName, AssetBundle a)
+        [ObjectSystem]
+        public class ABInfoAwakeSystem: AwakeSystem<ABInfo, string, AssetBundle>
         {
-            self.AssetBundle = a;
-            self.Name = abName;
-            self.RefCount = 1;
-            self.AlreadyLoadAssets = false;
+            public override void Awake(ABInfo self, string abName, AssetBundle a)
+            {
+                self.AssetBundle = a;
+                self.Name = abName;
+                self.RefCount = 1;
+                self.AlreadyLoadAssets = false;
+            }
         }
-    }
 
-    [ObjectSystem]
-    public class ABInfoDestroySystem: DestroySystem<ABInfo>
-    {
-        public override void Destroy(ABInfo self)
+        [ObjectSystem]
+        public class ABInfoDestroySystem: DestroySystem<ABInfo>
+        {
+            public override void Destroy(ABInfo self)
+            {
+                //Log.Debug($"desdroy assetbundle: {self.Name}");
+
+                self.RefCount = 0;
+                self.Name = "";
+                self.AlreadyLoadAssets = false;
+                self.AssetBundle = null;
+            }
+        }
+        
+        public static void Destroy(this ABInfo self, bool unload = true)
         {
-            //Log.Debug($"desdroy assetbundle: {this.Name}");
+            if (self.AssetBundle != null)
+            {
+                self.AssetBundle.Unload(unload);
+            }
 
-            self.RefCount = 0;
-            self.Name = "";
-            self.AlreadyLoadAssets = false;
-            self.AssetBundle = null;
+            self.Dispose();
         }
     }
 
@@ -42,19 +56,10 @@ namespace ET
         public AssetBundle AssetBundle;
 
         public bool AlreadyLoadAssets;
-
-        public void Destroy(bool unload = true)
-        {
-            if (this.AssetBundle != null)
-            {
-                this.AssetBundle.Unload(unload);
-            }
-
-            this.Dispose();
-        }
     }
 
     // 用于字符串转换,减少GC
+    [FriendClass(typeof(ResourcesComponent))]
     public static class AssetBundleHelper
     {
         public static async ETTask<AssetBundle> UnityLoadBundleAsync(string path)
@@ -118,70 +123,51 @@ namespace ET
         }
     }
 
-    [ObjectSystem]
-    public class ResourcesComponentAwakeSystem: AwakeSystem<ResourcesComponent>
-    {
-        public override void Awake(ResourcesComponent self)
-        {
-            self.Awake();
-        }
-    }
-
-    public class ResourcesComponent: Entity, IAwake
-    {
-        public static ResourcesComponent Instance { get; set; }
-
-        private AssetBundleManifest AssetBundleManifestObject { get; set; }
-
-        public Dictionary<int, string> IntToStringDict = new Dictionary<int, string>();
-
-        public Dictionary<string, string> StringToABDict = new Dictionary<string, string>();
-
-        public Dictionary<string, string> BundleNameToLowerDict = new Dictionary<string, string>() { { "StreamingAssets", "StreamingAssets" } };
-
-        private readonly Dictionary<string, Dictionary<string, UnityEngine.Object>> resourceCache =
-                new Dictionary<string, Dictionary<string, UnityEngine.Object>>();
 
-        private readonly Dictionary<string, ABInfo> bundles = new Dictionary<string, ABInfo>();
 
-        public void Awake()
+    [FriendClass(typeof(ABInfo))]
+    [FriendClass(typeof(ResourcesComponent))]
+    public static class ResourcesComponentSystem
+    {
+        [ObjectSystem]
+        public class ResourcesComponentAwakeSystem: AwakeSystem<ResourcesComponent>
         {
-            Instance = this;
-
-            if (Define.IsAsync)
+            public override void Awake(ResourcesComponent self)
             {
-                LoadOneBundle("StreamingAssets");
-                AssetBundleManifestObject = (AssetBundleManifest)GetAsset("StreamingAssets", "AssetBundleManifest");
+                ResourcesComponent.Instance = self;
+
+                if (Define.IsAsync)
+                {
+                    self.LoadOneBundle("StreamingAssets");
+                    self.AssetBundleManifestObject = (AssetBundleManifest)self.GetAsset("StreamingAssets", "AssetBundleManifest");
+                }
             }
         }
-
-        public override void Dispose()
+        
+        [ObjectSystem]
+        public class ResourcesComponentDestroySystem: DestroySystem<ResourcesComponent>
         {
-            if (this.IsDisposed)
+            public override void Destroy(ResourcesComponent self)
             {
-                return;
-            }
+                ResourcesComponent.Instance = null;
 
-            base.Dispose();
-
-            Instance = null;
+                foreach (var abInfo in self.bundles)
+                {
+                    abInfo.Value.Destroy();
+                }
 
-            foreach (var abInfo in this.bundles)
-            {
-                abInfo.Value.Destroy();
+                self.bundles.Clear();
+                self.resourceCache.Clear();
+                self.IntToStringDict.Clear();
+                self.StringToABDict.Clear();
+                self.BundleNameToLowerDict.Clear();
             }
-
-            this.bundles.Clear();
-            this.resourceCache.Clear();
-            this.IntToStringDict.Clear();
-            this.StringToABDict.Clear();
-            this.BundleNameToLowerDict.Clear();
         }
 
-        private string[] GetDependencies(string assetBundleName)
+        private static string[] GetDependencies(this ResourcesComponent self, string assetBundleName)
         {
             string[] dependencies = Array.Empty<string>();
-            if (DependenciesCache.TryGetValue(assetBundleName, out dependencies))
+            if (self.DependenciesCache.TryGetValue(assetBundleName, out dependencies))
             {
                 return dependencies;
             }
@@ -195,26 +181,26 @@ namespace ET
             }
             else
             {
-                dependencies = this.AssetBundleManifestObject.GetAllDependencies(assetBundleName);
+                dependencies = self.AssetBundleManifestObject.GetAllDependencies(assetBundleName);
             }
 
-            DependenciesCache.Add(assetBundleName, dependencies);
+            self.DependenciesCache.Add(assetBundleName, dependencies);
             return dependencies;
         }
 
-        private string[] GetSortedDependencies(string assetBundleName)
+        private static string[] GetSortedDependencies(this ResourcesComponent self, string assetBundleName)
         {
             var info = new Dictionary<string, int>();
             var parents = new List<string>();
-            CollectDependencies(parents, assetBundleName, info);
+            self.CollectDependencies(parents, assetBundleName, info);
             string[] ss = info.OrderBy(x => x.Value).Select(x => x.Key).ToArray();
             return ss;
         }
 
-        private void CollectDependencies(List<string> parents, string assetBundleName, Dictionary<string, int> info)
+        private static void CollectDependencies(this ResourcesComponent self, List<string> parents, string assetBundleName, Dictionary<string, int> info)
         {
             parents.Add(assetBundleName);
-            string[] deps = GetDependencies(assetBundleName);
+            string[] deps = self.GetDependencies(assetBundleName);
             foreach (string parent in parents)
             {
                 if (!info.ContainsKey(parent))
@@ -232,24 +218,23 @@ namespace ET
                     throw new Exception($"包有循环依赖,请重新标记: {assetBundleName} {dep}");
                 }
 
-                CollectDependencies(parents, dep, info);
+                self.CollectDependencies(parents, dep, info);
             }
 
             parents.RemoveAt(parents.Count - 1);
         }
 
-        // 缓存包依赖,不用每次计算
-        private readonly Dictionary<string, string[]> DependenciesCache = new Dictionary<string, string[]>();
 
-        public bool Contains(string bundleName)
+
+        public static bool Contains(this ResourcesComponent self, string bundleName)
         {
-            return this.bundles.ContainsKey(bundleName);
+            return self.bundles.ContainsKey(bundleName);
         }
 
-        public Dictionary<string, UnityEngine.Object> GetBundleAll(string bundleName)
+        public static Dictionary<string, UnityEngine.Object> GetBundleAll(this ResourcesComponent self, string bundleName)
         {
             Dictionary<string, UnityEngine.Object> dict;
-            if (!this.resourceCache.TryGetValue(bundleName.BundleNameToLower(), out dict))
+            if (!self.resourceCache.TryGetValue(bundleName.BundleNameToLower(), out dict))
             {
                 throw new Exception($"not found asset: {bundleName}");
             }
@@ -257,10 +242,10 @@ namespace ET
             return dict;
         }
 
-        public UnityEngine.Object GetAsset(string bundleName, string prefab)
+        public static UnityEngine.Object GetAsset(this ResourcesComponent self, string bundleName, string prefab)
         {
             Dictionary<string, UnityEngine.Object> dict;
-            if (!this.resourceCache.TryGetValue(bundleName.BundleNameToLower(), out dict))
+            if (!self.resourceCache.TryGetValue(bundleName.BundleNameToLower(), out dict))
             {
                 throw new Exception($"not found asset: {bundleName} {prefab}");
             }
@@ -275,11 +260,11 @@ namespace ET
         }
 
         // 一帧卸载一个包,避免卡死
-        public async ETTask UnloadBundleAsync(string assetBundleName, bool unload = true)
+        public static async ETTask UnloadBundleAsync(this ResourcesComponent self, string assetBundleName, bool unload = true)
         {
             assetBundleName = assetBundleName.BundleNameToLower();
 
-            string[] dependencies = GetSortedDependencies(assetBundleName);
+            string[] dependencies = self.GetSortedDependencies(assetBundleName);
 
             //Log.Debug($"-----------dep unload start {assetBundleName} dep: {dependencies.ToList().ListToString()}");
             foreach (string dependency in dependencies)
@@ -288,7 +273,7 @@ namespace ET
                 try
                 {
                     coroutineLock = await CoroutineLockComponent.Instance.Wait(CoroutineLockType.Resources, assetBundleName.GetHashCode());
-                    this.UnloadOneBundle(dependency, unload);
+                    self.UnloadOneBundle(dependency, unload);
                     await TimerComponent.Instance.WaitFrameAsync();
                 }
                 finally
@@ -300,27 +285,27 @@ namespace ET
         }
 
         // 只允许场景设置unload为false
-        public void UnloadBundle(string assetBundleName, bool unload = true)
+        public static void UnloadBundle(this ResourcesComponent self, string assetBundleName, bool unload = true)
         {
             assetBundleName = assetBundleName.BundleNameToLower();
 
-            string[] dependencies = GetSortedDependencies(assetBundleName);
+            string[] dependencies = self.GetSortedDependencies(assetBundleName);
 
             //Log.Debug($"-----------dep unload start {assetBundleName} dep: {dependencies.ToList().ListToString()}");
             foreach (string dependency in dependencies)
             {
-                this.UnloadOneBundle(dependency, unload);
+                self.UnloadOneBundle(dependency, unload);
             }
 
             //Log.Debug($"-----------dep unload finish {assetBundleName} dep: {dependencies.ToList().ListToString()}");
         }
 
-        private void UnloadOneBundle(string assetBundleName, bool unload = true)
+        private static void UnloadOneBundle(this ResourcesComponent self, string assetBundleName, bool unload = true)
         {
             assetBundleName = assetBundleName.BundleNameToLower();
 
             ABInfo abInfo;
-            if (!this.bundles.TryGetValue(assetBundleName, out abInfo))
+            if (!self.bundles.TryGetValue(assetBundleName, out abInfo))
             {
                 return;
             }
@@ -335,10 +320,10 @@ namespace ET
             }
 
             //Log.Debug($"---------------truly unload one bundle {assetBundleName} refcount: {abInfo.RefCount}");
-            this.bundles.Remove(assetBundleName);
-            this.resourceCache.Remove(assetBundleName);
+            self.bundles.Remove(assetBundleName);
+            self.resourceCache.Remove(assetBundleName);
             abInfo.Destroy(unload);
-            // Log.Debug($"cache count: {this.cacheDictionary.Count}");
+            // Log.Debug($"cache count: {self.cacheDictionary.Count}");
         }
 
         /// <summary>
@@ -346,11 +331,11 @@ namespace ET
         /// </summary>
         /// <param name="assetBundleName"></param>
         /// <returns></returns>
-        public void LoadBundle(string assetBundleName)
+        public static void LoadBundle(this ResourcesComponent self, string assetBundleName)
         {
             assetBundleName = assetBundleName.ToLower();
 
-            string[] dependencies = GetSortedDependencies(assetBundleName);
+            string[] dependencies = self.GetSortedDependencies(assetBundleName);
             //Log.Debug($"-----------dep load start {assetBundleName} dep: {dependencies.ToList().ListToString()}");
             foreach (string dependency in dependencies)
             {
@@ -359,29 +344,29 @@ namespace ET
                     continue;
                 }
 
-                this.LoadOneBundle(dependency);
+                self.LoadOneBundle(dependency);
             }
 
             //Log.Debug($"-----------dep load finish {assetBundleName} dep: {dependencies.ToList().ListToString()}");
         }
 
-        private void AddResource(string bundleName, string assetName, UnityEngine.Object resource)
+        private static void AddResource(this ResourcesComponent self, string bundleName, string assetName, UnityEngine.Object resource)
         {
             Dictionary<string, UnityEngine.Object> dict;
-            if (!this.resourceCache.TryGetValue(bundleName.BundleNameToLower(), out dict))
+            if (!self.resourceCache.TryGetValue(bundleName.BundleNameToLower(), out dict))
             {
                 dict = new Dictionary<string, UnityEngine.Object>();
-                this.resourceCache[bundleName] = dict;
+                self.resourceCache[bundleName] = dict;
             }
 
             dict[assetName] = resource;
         }
 
-        private void LoadOneBundle(string assetBundleName)
+        private static void LoadOneBundle(this ResourcesComponent self, string assetBundleName)
         {
             assetBundleName = assetBundleName.BundleNameToLower();
             ABInfo abInfo;
-            if (this.bundles.TryGetValue(assetBundleName, out abInfo))
+            if (self.bundles.TryGetValue(assetBundleName, out abInfo))
             {
                 ++abInfo.RefCount;
                 //Log.Debug($"---------------load one bundle {assetBundleName} refcount: {abInfo.RefCount}");
@@ -398,13 +383,13 @@ namespace ET
                     {
                         string assetName = Path.GetFileNameWithoutExtension(s);
                         UnityEngine.Object resource = Define.LoadAssetAtPath(s);
-                        AddResource(assetBundleName, assetName, resource);
+                        self.AddResource(assetBundleName, assetName, resource);
                     }
 
                     if (realPath.Length > 0)
                     {
-                        abInfo = this.AddChild<ABInfo, string, AssetBundle>(assetBundleName, null);
-                        this.bundles[assetBundleName] = abInfo;
+                        abInfo = self.AddChild<ABInfo, string, AssetBundle>(assetBundleName, null);
+                        self.bundles[assetBundleName] = abInfo;
                         //Log.Debug($"---------------load one bundle {assetBundleName} refcount: {abInfo.RefCount}");
                     }
                     else
@@ -441,12 +426,12 @@ namespace ET
                 var assets = assetBundle.LoadAllAssets();
                 foreach (UnityEngine.Object asset in assets)
                 {
-                    AddResource(assetBundleName, asset.name, asset);
+                    self.AddResource(assetBundleName, asset.name, asset);
                 }
             }
 
-            abInfo = this.AddChild<ABInfo, string, AssetBundle>(assetBundleName, assetBundle);
-            this.bundles[assetBundleName] = abInfo;
+            abInfo = self.AddChild<ABInfo, string, AssetBundle>(assetBundleName, assetBundle);
+            self.bundles[assetBundleName] = abInfo;
 
             //Log.Debug($"---------------load one bundle {assetBundleName} refcount: {abInfo.RefCount}");
         }
@@ -454,11 +439,11 @@ namespace ET
         /// <summary>
         /// 异步加载assetbundle, 加载ab包分两部分,第一部分是从硬盘加载,第二部分加载all assets。两者不能同时并发
         /// </summary>
-        public async ETTask LoadBundleAsync(string assetBundleName)
+        public static async ETTask LoadBundleAsync(this ResourcesComponent self, string assetBundleName)
         {
             assetBundleName = assetBundleName.BundleNameToLower();
 
-            string[] dependencies = GetSortedDependencies(assetBundleName);
+            string[] dependencies = self.GetSortedDependencies(assetBundleName);
             //Log.Debug($"-----------dep load async start {assetBundleName} dep: {dependencies.ToList().ListToString()}");
 
             using (ListComponent<ABInfo> abInfos = ListComponent<ABInfo>.Create())
@@ -469,7 +454,7 @@ namespace ET
                     try
                     {
                         coroutineLock = await CoroutineLockComponent.Instance.Wait(CoroutineLockType.Resources, dependency.GetHashCode());
-                        ABInfo abInfo = await this.LoadOneBundleAsync(dependency);
+                        ABInfo abInfo = await self.LoadOneBundleAsync(dependency);
                         if (abInfo == null || abInfo.RefCount > 1)
                         {
                             return;
@@ -496,18 +481,18 @@ namespace ET
                     tasks.Clear();
                     foreach (ABInfo abInfo in abInfos)
                     {
-                        tasks.Add(LoadOneBundleAllAssets(abInfo));
+                        tasks.Add(self.LoadOneBundleAllAssets(abInfo));
                     }
                     await ETTaskHelper.WaitAll(tasks);
                 }
             }
         }
 
-        private async ETTask<ABInfo> LoadOneBundleAsync(string assetBundleName)
+        private static async ETTask<ABInfo> LoadOneBundleAsync(this ResourcesComponent self, string assetBundleName)
         {
             assetBundleName = assetBundleName.BundleNameToLower();
             ABInfo abInfo;
-            if (this.bundles.TryGetValue(assetBundleName, out abInfo))
+            if (self.bundles.TryGetValue(assetBundleName, out abInfo))
             {
                 ++abInfo.RefCount;
                 //Log.Debug($"---------------load one bundle {assetBundleName} refcount: {abInfo.RefCount}");
@@ -525,13 +510,13 @@ namespace ET
                     {
                         string assetName = Path.GetFileNameWithoutExtension(s);
                         UnityEngine.Object resource = Define.LoadAssetAtPath(s);
-                        AddResource(assetBundleName, assetName, resource);
+                        self.AddResource(assetBundleName, assetName, resource);
                     }
 
                     if (realPath.Length > 0)
                     {
-                        abInfo = this.AddChild<ABInfo, string, AssetBundle>(assetBundleName, null);
-                        this.bundles[assetBundleName] = abInfo;
+                        abInfo = self.AddChild<ABInfo, string, AssetBundle>(assetBundleName, null);
+                        self.bundles[assetBundleName] = abInfo;
                         //Log.Debug($"---------------load one bundle {assetBundleName} refcount: {abInfo.RefCount}");
                     }
                     else
@@ -564,14 +549,14 @@ namespace ET
                 Log.Warning($"assets bundle not found: {assetBundleName}");
                 return null;
             }
-            abInfo = this.AddChild<ABInfo, string, AssetBundle>(assetBundleName, assetBundle);
-            this.bundles[assetBundleName] = abInfo;
+            abInfo = self.AddChild<ABInfo, string, AssetBundle>(assetBundleName, assetBundle);
+            self.bundles[assetBundleName] = abInfo;
             return abInfo;
             //Log.Debug($"---------------load one bundle {assetBundleName} refcount: {abInfo.RefCount}");
         }
 
         // 加载ab包中的all assets
-        private async ETTask LoadOneBundleAllAssets(ABInfo abInfo)
+        private static async ETTask LoadOneBundleAllAssets(this ResourcesComponent self, ABInfo abInfo)
         {
             CoroutineLock coroutineLock = null;
             try
@@ -590,7 +575,7 @@ namespace ET
 
                     foreach (UnityEngine.Object asset in assets)
                     {
-                        AddResource(abInfo.Name, asset.name, asset);
+                        self.AddResource(abInfo.Name, asset.name, asset);
                     }
                 }
 
@@ -602,10 +587,10 @@ namespace ET
             }
         }
 
-        public string DebugString()
+        public static string DebugString(this ResourcesComponent self)
         {
             StringBuilder sb = new StringBuilder();
-            foreach (ABInfo abInfo in this.bundles.Values)
+            foreach (ABInfo abInfo in self.bundles.Values)
             {
                 sb.Append($"{abInfo.Name}:{abInfo.RefCount}\n");
             }
@@ -613,4 +598,25 @@ namespace ET
             return sb.ToString();
         }
     }
+    
+    public class ResourcesComponent: Entity, IAwake, IDestroy
+    {
+        public static ResourcesComponent Instance { get; set; }
+
+        public AssetBundleManifest AssetBundleManifestObject { get; set; }
+
+        public Dictionary<int, string> IntToStringDict = new Dictionary<int, string>();
+
+        public Dictionary<string, string> StringToABDict = new Dictionary<string, string>();
+
+        public Dictionary<string, string> BundleNameToLowerDict = new Dictionary<string, string>() { { "StreamingAssets", "StreamingAssets" } };
+
+        public readonly Dictionary<string, Dictionary<string, UnityEngine.Object>> resourceCache =
+                new Dictionary<string, Dictionary<string, UnityEngine.Object>>();
+
+        public readonly Dictionary<string, ABInfo> bundles = new Dictionary<string, ABInfo>();
+        
+        // 缓存包依赖,不用每次计算
+        public readonly Dictionary<string, string[]> DependenciesCache = new Dictionary<string, string[]>();
+    }
 }

+ 47 - 43
Unity/Codes/ModelView/Client/Resource/ResourcesLoaderComponent.cs

@@ -2,76 +2,75 @@ using System.Collections.Generic;
 
 namespace ET
 {
-    [ObjectSystem]
-    public class ResourcesLoaderComponentDestroySystem: DestroySystem<ResourcesLoaderComponent>
+    [FriendClass(typeof(ResourcesLoaderComponent))]
+    public static class ResourcesLoaderComponentSystem
     {
-        public override void Destroy(ResourcesLoaderComponent self)
-        {
-            async ETTask UnLoadAsync()
+        [ObjectSystem]
+            public class ResourcesLoaderComponentDestroySystem: DestroySystem<ResourcesLoaderComponent>
             {
-                using (ListComponent<string> list = ListComponent<string>.Create())
+                public override void Destroy(ResourcesLoaderComponent self)
                 {
-                    list.AddRange(self.LoadedResource);
-                    self.LoadedResource = null;
-
-                    if (TimerComponent.Instance == null)
+                    async ETTask UnLoadAsync()
                     {
-                        return;
-                    }
-                    
-                    // 延迟5秒卸载包,因为包卸载是引用计数,5秒之内假如重新有逻辑加载了这个包,那么可以避免一次卸载跟加载
-                    await TimerComponent.Instance.WaitAsync(5000);
-
-                    foreach (string abName in list)
-                    {
-                        CoroutineLock coroutineLock = null;
-                        try
+                        using (ListComponent<string> list = ListComponent<string>.Create())
                         {
-                            coroutineLock =
-                                    await CoroutineLockComponent.Instance.Wait(CoroutineLockType.ResourcesLoader, abName.GetHashCode(), 0);
+                            list.AddRange(self.LoadedResource);
+                            self.LoadedResource = null;
+        
+                            if (TimerComponent.Instance == null)
+                            {
+                                return;
+                            }
+                            
+                            // 延迟5秒卸载包,因为包卸载是引用计数,5秒之内假如重新有逻辑加载了这个包,那么可以避免一次卸载跟加载
+                            await TimerComponent.Instance.WaitAsync(5000);
+        
+                            foreach (string abName in list)
                             {
-                                if (ResourcesComponent.Instance == null)
+                                CoroutineLock coroutineLock = null;
+                                try
                                 {
-                                    return;
+                                    coroutineLock =
+                                            await CoroutineLockComponent.Instance.Wait(CoroutineLockType.ResourcesLoader, abName.GetHashCode(), 0);
+                                    {
+                                        if (ResourcesComponent.Instance == null)
+                                        {
+                                            return;
+                                        }
+        
+                                        await ResourcesComponent.Instance.UnloadBundleAsync(abName);
+                                    }
+                                }
+                                finally
+                                {
+                                    coroutineLock?.Dispose();
                                 }
-
-                                await ResourcesComponent.Instance.UnloadBundleAsync(abName);
                             }
                         }
-                        finally
-                        {
-                            coroutineLock?.Dispose();
-                        }
                     }
+        
+                    UnLoadAsync().Coroutine();
                 }
             }
-
-            UnLoadAsync().Coroutine();
-        }
-    }
-    
-    public class ResourcesLoaderComponent: Entity, IAwake, IDestroy
-    {
-        public HashSet<string> LoadedResource = new HashSet<string>();
-
-        public async ETTask LoadAsync(string ab)
+        
+        public static async ETTask LoadAsync(this ResourcesLoaderComponent self, string ab)
         {
             CoroutineLock coroutineLock = null;
             try
             {
                 coroutineLock = await CoroutineLockComponent.Instance.Wait(CoroutineLockType.ResourcesLoader, ab.GetHashCode(), 0);
-                if (this.IsDisposed)
+                if (self.IsDisposed)
                 {
                     Log.Error($"resourceload already disposed {ab}");
                     return;
                 }
 
-                if (this.LoadedResource.Contains(ab))
+                if (self.LoadedResource.Contains(ab))
                 {
                     return;
                 }
 
-                LoadedResource.Add(ab);
+                self.LoadedResource.Add(ab);
                 await ResourcesComponent.Instance.LoadBundleAsync(ab);
             }
             finally
@@ -80,4 +79,9 @@ namespace ET
             }
         }
     }
+    
+    public class ResourcesLoaderComponent: Entity, IAwake, IDestroy
+    {
+        public HashSet<string> LoadedResource = new HashSet<string>();
+    }
 }

+ 70 - 76
Unity/Codes/ModelView/Module/UI/UI.cs

@@ -1,89 +1,83 @@
 using System.Collections.Generic;
-
 using UnityEngine;
 
 namespace ET
 {
-	public sealed class UI: Entity, IAwake<string, GameObject>
-	{
-		[ObjectSystem]
-		public class UIAwakeSystem : AwakeSystem<UI, string, GameObject>
-		{
-			public override void Awake(UI self, string name, GameObject gameObject)
-			{
-
-				self.Awake(name, gameObject);
-			}
-		}
-		
-		public GameObject GameObject { get; set; }
-		
-		public string Name { get; private set; }
-
-		public Dictionary<string, UI> nameChildren = new Dictionary<string, UI>();
+    [FriendClass(typeof(UI))]
+    public static class UISystem
+    {
+        [ObjectSystem]
+        public class UIAwakeSystem : AwakeSystem<UI, string, GameObject>
+        {
+            public override void Awake(UI self, string name, GameObject gameObject)
+            {
+                self.nameChildren.Clear();
+                gameObject.layer = LayerMask.NameToLayer(LayerNames.UI);
+                self.Name = name;
+                self.GameObject = gameObject;
+            }
+        }
 		
-		public void Awake(string name, GameObject gameObject)
-		{
-			this.nameChildren.Clear();
-			gameObject.layer = LayerMask.NameToLayer(LayerNames.UI);
-			this.Name = name;
-			this.GameObject = gameObject;
-		}
-
-		public override void Dispose()
-		{
-			if (this.IsDisposed)
-			{
-				return;
-			}
+        [ObjectSystem]
+        public class UIDestroySystem : DestroySystem<UI>
+        {
+            public override void Destroy(UI self)
+            {
+                foreach (UI ui in self.nameChildren.Values)
+                {
+                    ui.Dispose();
+                }
 			
-			base.Dispose();
+                UnityEngine.Object.Destroy(self.GameObject);
+                self.nameChildren.Clear();
+            }
+        }
 
-			foreach (UI ui in this.nameChildren.Values)
-			{
-				ui.Dispose();
-			}
-			
-			UnityEngine.Object.Destroy(this.GameObject);
-			this.nameChildren.Clear();
-		}
+        public static void SetAsFirstSibling(this UI self)
+        {
+            self.GameObject.transform.SetAsFirstSibling();
+        }
 
-		public void SetAsFirstSibling()
-		{
-			this.GameObject.transform.SetAsFirstSibling();
-		}
+        public static void Add(this UI self, UI ui)
+        {
+            self.nameChildren.Add(ui.Name, ui);
+        }
 
-		public void Add(UI ui)
-		{
-			this.nameChildren.Add(ui.Name, ui);
-		}
+        public static void Remove(this UI self, string name)
+        {
+            UI ui;
+            if (!self.nameChildren.TryGetValue(name, out ui))
+            {
+                return;
+            }
+            self.nameChildren.Remove(name);
+            ui.Dispose();
+        }
 
-		public void Remove(string name)
-		{
-			UI ui;
-			if (!this.nameChildren.TryGetValue(name, out ui))
-			{
-				return;
-			}
-			this.nameChildren.Remove(name);
-			ui.Dispose();
-		}
+        public static UI Get(this UI self, string name)
+        {
+            UI child;
+            if (self.nameChildren.TryGetValue(name, out child))
+            {
+                return child;
+            }
+            GameObject childGameObject = self.GameObject.transform.Find(name)?.gameObject;
+            if (childGameObject == null)
+            {
+                return null;
+            }
+            child = self.AddChild<UI, string, GameObject>(name, childGameObject);
+            self.Add(child);
+            return child;
+        }
+    }
+	
+    public sealed class UI: Entity, IAwake<string, GameObject>, IDestroy
+    {
+        public GameObject GameObject { get; set; }
+		
+        public string Name { get; set; }
 
-		public UI Get(string name)
-		{
-			UI child;
-			if (this.nameChildren.TryGetValue(name, out child))
-			{
-				return child;
-			}
-			GameObject childGameObject = this.GameObject.transform.Find(name)?.gameObject;
-			if (childGameObject == null)
-			{
-				return null;
-			}
-			child = this.AddChild<UI, string, GameObject>(name, childGameObject);
-			this.Add(child);
-			return child;
-		}
-	}
+        public Dictionary<string, UI> nameChildren = new Dictionary<string, UI>();
+    }
 }