<|start_filename|>Runtime/Common/Singleton/MonoSingletonProperty.cs<|end_filename|>
namespace Framework
{
    using UnityEngine;

    public static class MonoSingletonProperty<T> where T : MonoBehaviour
    {
        private static T instance = null;

        public static T Ins
        {
            get
            {
                if (null == instance)
                {
                    instance = MonoSingletonCreator.CreateMonoSingleton<T>();
                }

                return instance;
            }
        }

        public static void Dispose()
        {
            Object.Destroy(instance.gameObject);
            instance = null;
        }
    }
}

<|start_filename|>Runtime/Tool/CommonHelper.cs<|end_filename|>
﻿using System;
using System.IO;
using System.Text;
using UnityEditor;
using UnityEngine;
using UnityEngine.SceneManagement;

namespace Framework.Helper
{
    public static class CommonHelper
    {
        /// <summary>
        /// 资源清理和垃圾回收
        /// </summary>
        public static void ClearMemory()
        {
            Resources.UnloadUnusedAssets();
            GC.Collect();
        }

        /// <summary>
        /// 网络可用
        /// </summary>
        public static bool NetAvailable => Application.internetReachability != NetworkReachability.NotReachable;

        /// <summary>
        /// 是否是无线
        /// </summary>
        public static bool IsWifi =>
            Application.internetReachability == NetworkReachability.ReachableViaLocalAreaNetwork;


        /// <summary>
        /// 获取当前运行的设备平台信息
        /// </summary>
        /// <returns></returns>
        public static string GetDeviceInfo()
        {
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.Append("Device And Sysinfo:\r\n");
            stringBuilder.Append(string.Format("DeviceModel: {0} \r\n", SystemInfo.deviceModel));
            stringBuilder.Append(string.Format("DeviceName: {0} \r\n", SystemInfo.deviceName));
            stringBuilder.Append(string.Format("DeviceType: {0} \r\n", SystemInfo.deviceType));
            stringBuilder.Append(string.Format("BatteryLevel: {0} \r\n", SystemInfo.batteryLevel));
            stringBuilder.Append(string.Format("DeviceUniqueIdentifier: {0} \r\n", SystemInfo.deviceUniqueIdentifier));
            stringBuilder.Append(string.Format("SystemMemorySize: {0} \r\n", SystemInfo.systemMemorySize));
            stringBuilder.Append(string.Format("OperatingSystem: {0} \r\n", SystemInfo.operatingSystem));
            stringBuilder.Append(string.Format("GraphicsDeviceID: {0} \r\n", SystemInfo.graphicsDeviceID));
            stringBuilder.Append(string.Format("GraphicsDeviceName: {0} \r\n", SystemInfo.graphicsDeviceName));
            stringBuilder.Append(string.Format("GraphicsDeviceType: {0} \r\n", SystemInfo.graphicsDeviceType));
            stringBuilder.Append(string.Format("GraphicsDeviceVendor: {0} \r\n", SystemInfo.graphicsDeviceVendor));
            stringBuilder.Append(string.Format("GraphicsDeviceVendorID: {0} \r\n", SystemInfo.graphicsDeviceVendorID));
            stringBuilder.Append(string.Format("GraphicsDeviceVersion: {0} \r\n", SystemInfo.graphicsDeviceVersion));
            stringBuilder.Append(string.Format("GraphicsMemorySize: {0} \r\n", SystemInfo.graphicsMemorySize));
            stringBuilder.Append(string.Format("GraphicsMultiThreaded: {0} \r\n", SystemInfo.graphicsMultiThreaded));
            stringBuilder.Append(string.Format("SupportedRenderTargetCount: {0} \r\n",
                SystemInfo.supportedRenderTargetCount));
            return stringBuilder.ToString();
        }

        private static bool? isIpad;

        public static bool IsPad
        {
            get
            {
                if (isIpad != null) return isIpad.Value;
                string type = SystemInfo.deviceModel.ToLower().Trim();
                switch (type.Substring(0, 3))
                {
                    case "iph":
                        //iPhone机型
                        isIpad = false;
                        break;
                    case "ipa":
                        //iPad机型
                        isIpad = true;
                        break;
                    default:
                        //其他
                        isIpad = false;
                        break;
                }

                return isIpad.Value;
            }
        }

        /// <summary>
        /// 获取设备的电量
        /// </summary>
        /// <returns></returns>
        public static float GetBatteryLevel()
        {
            if (Application.isMobilePlatform)
            {
                return SystemInfo.batteryLevel;
            }

            return 1;
        }

        /// <summary>
        /// 获取设备的电池状态
        /// </summary>
        /// <returns></returns>
        public static BatteryStatus GetBatteryStatus()
        {
            return SystemInfo.batteryStatus;
        }

        /// <summary>
        /// 获取设备网络的状况
        /// </summary>
        /// <returns></returns>
        public static NetworkReachability GetNetworkStatus()
        {
            return Application.internetReachability;
        }
        
        public static long CurrentMillTime()
        {
            TimeSpan tss = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            long millTime = Convert.ToInt64(tss.TotalMilliseconds);
            return millTime;
        }
        
        #region Editor

#if UNITY_EDITOR

        public static GameObject[] GetCurSceneRootObjs()
        {
            Scene curScene = SceneManager.GetActiveScene();
            return curScene.GetRootGameObjects();
        }

        public static T LoadScriptableAsset<T>(string assetPath, bool createDefault = true) where T : ScriptableObject
        {
            T asset = AssetDatabase.LoadAssetAtPath<T>(assetPath + ".asset");
            if (asset == null && createDefault)
            {
                asset = CreateScriptableAsset<T>(assetPath);
            }

            return asset;
        }

        public static T CreateScriptableAsset<T>(string assetPath, T obj = null) where T : ScriptableObject
        {
            if (obj == null) obj = ScriptableObject.CreateInstance<T>();
            int pIndex = assetPath.LastIndexOfAny(new[] {'\\', '/'});
            if (pIndex > 0)
            {
                string parentFolderPath = assetPath.Substring(0, pIndex);
                if (!Directory.Exists(parentFolderPath))
                {
                    Directory.CreateDirectory(parentFolderPath);
                }
            }

            AssetDatabase.CreateAsset(obj, assetPath + ".asset");
            return obj;
        }

        public static void ReimportAsset<T>(bool includePackages = true) where T : UnityEngine.Object
        {
            string filter = string.Format("t:{0}", typeof(T)).Replace("UnityEngine.", "");
            string progressTitle = "reimport assets:" + filter;
            string[] searchFolders = includePackages ? null : new[] {"Assets"};
            string[] guids = AssetDatabase.FindAssets(filter, searchFolders);
            EditorUtility.DisplayProgressBar(progressTitle, "", 0);
            Debug.Log($"waiting for {guids.Length} objs to import");
            for (int i = 0; i < guids.Length; ++i)
            {
                string assetPath = AssetDatabase.GUIDToAssetPath(guids[i]);
                EditorUtility.DisplayProgressBar(progressTitle, assetPath, (float) i / guids.Length);
                AssetDatabase.ImportAsset(assetPath);
            }

            EditorUtility.ClearProgressBar();
            Debug.Log("reimport done");
        }
#endif

        #endregion
        
    }
}

<|start_filename|>Runtime/Common/Singleton/Singleton.cs<|end_filename|>
using System;
using Tool;

namespace Framework
{
	public class Singleton<T> where T : class
	{
		private static readonly object locker = new object ();

		private static T instance;

		public static T Ins
		{
			get
			{
				lock ( locker )
				{
					if ( instance == null )
					{
						lock ( locker )
						{
							instance = ReflectionHelper.CreateInstance<T>();
						}
					}
				}

				return instance;
			}
		}
	}
}


<|start_filename|>Runtime/Common/Singleton/MonoSingletonCreator.cs<|end_filename|>
using UnityEngine;

namespace Framework
{
    public class MonoSingletonCreator
    {
        public static T CreateMonoSingleton<T>() where T : MonoBehaviour
        {
            T instance = null;

            instance = Object.FindObjectOfType<T>();

            if (instance != null)
            {
                return instance;
            }

            if (instance == null)
            {
                var obj = new GameObject(typeof(T).Name);
                if (Application.isPlaying)
                    Object.DontDestroyOnLoad(obj);
                instance = obj.AddComponent<T>();
            }
            
            return instance;
        }
    }
}

<|start_filename|>Runtime/UI/Wrap/Base/ICustomRes.cs<|end_filename|>
using Framework.Assets;

namespace Framework
{
    public interface ICustomRes
    {
        IRes GetRes();
    }
}

<|start_filename|>Runtime/UI/Core/TransformPath.cs<|end_filename|>
﻿using System;
using UnityEngine;

namespace Framework.UI.Core
{
    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
    public class TransformPath : Attribute
    {
        public string Path;

        public TransformPath(string path)
        {
            this.Path = path;
        }
    }
}

<|start_filename|>Runtime/UI/Component/ScrollView/SynergeticScrollRect.cs<|end_filename|>
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class SynergeticScrollRect : ScrollRect
{
    private ScrollRect fatherScrollRect;

    public void SetFatherScrollRect(ScrollRect fatherScrollRect)
    {
        this.fatherScrollRect = fatherScrollRect;
    }

    public override void OnBeginDrag(PointerEventData eventData)
    {
        base.OnBeginDrag(eventData);
        if (fatherScrollRect == null)
            return;
        fatherScrollRect.OnBeginDrag(eventData);
    }

    public override void OnDrag(PointerEventData eventData)
    {
        base.OnDrag(eventData);
        if (fatherScrollRect == null)
            return;
        fatherScrollRect.OnDrag(eventData);
    }

    public override void OnEndDrag(PointerEventData eventData)
    {
        base.OnEndDrag(eventData);
        if (fatherScrollRect == null)
            return;
        fatherScrollRect.OnEndDrag(eventData);
    }
}

<|start_filename|>Runtime/Assets/AddressableRes.cs<|end_filename|>
﻿#if ADDRESSABLE

using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using Framework.Asynchronous;
using Framework.Execution;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.SceneManagement;

namespace Framework.Assets
{
    public class AddressableRes : Res
    {
        private static bool initialized = false;

        public override string DownloadURL { get; set; }

        static IEnumerator Download(IProgressPromise<DownloadProgress> promise, AsyncOperationHandle handle)
        {
            while (!handle.IsDone)
            {
                promise.UpdateProgress(new DownloadProgress("", "", "", handle.PercentComplete));
                yield return null;
                if(handle.OperationException != null)
                    promise.SetException(handle.OperationException);
            }
            promise.SetException(handle.OperationException);
            promise.SetResult();
        }

        private static Type MonoType = typeof(MonoBehaviour);
        private List<AsyncOperationHandle> _handles = new List<AsyncOperationHandle>();

        public override async Task<string> CheckDownloadSize(string key)
        {
            var list = await Addressables.LoadResourceLocationsAsync(key);
            if (list.Count <= 0) return string.Empty;
            //判断有没有需要动态加载的资源
            var size = await Addressables.GetDownloadSizeAsync(key);
            if (size <= 0) return String.Empty;
            var kb = size / 1024;
            if (kb < 1024)
                return $"{kb}kb";
            return $"{kb / 1024:.00}mb";
        }
        

        protected override async void LoadScene(IProgressPromise<float, Scene> promise,string path, LoadSceneMode loadSceneMode)
        {
            var loader = Addressables.LoadSceneAsync(path, loadSceneMode);
            while (!loader.IsDone)
            {
                await Task.Yield();
                promise.UpdateProgress(loader.PercentComplete);
            }
            
            promise.UpdateProgress(1);
            promise.SetResult(loader.Result.Scene);
        }


#pragma warning disable 1998
        public override async Task<IProgressResult<DownloadProgress>> DownloadAssets(string key)
#pragma warning restore 1998
        {
            ProgressResult<DownloadProgress> progressResult = new ProgressResult<DownloadProgress>();
            var operation = Addressables.DownloadDependenciesAsync(key);
            Executors.RunOnCoroutineNoReturn(Download(progressResult, operation));            
            return progressResult;
        }

        protected override async void loadAssetAsync<T>(string key, IProgressPromise<float, T> promise)
        {
            var operation = Addressables.LoadAssetAsync<T>(key);
            while (!operation.IsDone)
            {
                promise.UpdateProgress(operation.PercentComplete);
                await Task.Yield();
            }
            if (typeof(T).IsSubclassOf(MonoType))
            {
                promise.SetResult((operation.Result as MonoBehaviour)?.GetComponent(typeof(T)));
            }
            else
            {
                promise.SetResult(operation.Result);
            }
            _handles.Add(operation);
        }

        public override IProgressResult<float, GameObject> InstantiateAsync(string key, Transform parent = null,
            bool instantiateInWorldSpace = false)
        {
            ProgressResult<float, GameObject> progressResult = new ProgressResult<float, GameObject>();
            instantiateAsync(getOperation(key, parent, instantiateInWorldSpace), progressResult);
            return progressResult;
        }

        public override IProgressResult<float, GameObject> InstantiateAsync(string key, Vector3 position, Quaternion rotation,
            Transform parent = null)
        {
            ProgressResult<float, GameObject> progressResult = new ProgressResult<float, GameObject>();
            instantiateAsync(getOperation(key, position, rotation, parent), progressResult);
            return progressResult;
        }

        private AsyncOperationHandle<GameObject> getOperation(object key, Transform parent = null,
            bool instantiateInWorldSpace = false, bool trackHandle = true)
        {
            return Addressables.InstantiateAsync(key, parent, instantiateInWorldSpace, trackHandle);
        }

        private AsyncOperationHandle<GameObject> getOperation(object key, Vector3 position, Quaternion rotation,
            Transform parent = null)
        {
            return Addressables.InstantiateAsync(key, position, rotation, parent);
        }

        private async void instantiateAsync(AsyncOperationHandle<GameObject> operation,
            IProgressPromise<float, GameObject> promise)
        {
            _handles.Add(operation);
            while (!operation.IsDone)
            {
                promise.UpdateProgress(operation.PercentComplete);
                await Task.Yield();
            }
            promise.UpdateProgress(1);
            promise.SetResult(operation.Result);
        }

        public override void Release()
        {
            for (int i = 0; i < _handles.Count; i++)
            {
                try
                {
                    Addressables.Release(_handles[i]);
                }
                catch (Exception)
                {
                }
            }
            _handles.Clear();
        }


        #region sync

        [Obsolete("仅做展示，暂时不使用同步加载", true)]
        public override GameObject Instantiate(string key, Transform parent = null, bool instantiateInWorldSpace = false)
        {
            if (!initialized)
                throw new Exception("We haven't init'd yet!");
            var op = Addressables.InstantiateAsync(key, parent, instantiateInWorldSpace);
            _handles.Add(op);
            if (!op.IsDone)
                throw new Exception("Sync Instantiate failed to finish! " + key);
            if (op.Result == null)
            {
                var message = "Sync Instantiate has null result " + key;
                if (op.OperationException != null)
                    message += " Exception: " + op.OperationException;
                throw new Exception(message);
            }
            return op.Result;
        }

        [Obsolete("仅做展示，暂时不使用同步加载", true)]
        public override T LoadAsset<T>(string key)
        {
            if (!initialized)
                throw new Exception("We haven't init'd yet!");
            var op = Addressables.LoadAssetAsync<T>(key);
            _handles.Add(op);
            if (!op.IsDone)
                throw new Exception("Sync LoadAsset failed to load in a sync way! " + key);
            if (op.Result == null)
            {
                var message = "Sync LoadAsset has null result " + key;
                if (op.OperationException != null)
                    message += " Exception: " + op.OperationException;
                throw new Exception(message);
            }
            return op.Result;
        }

        #endregion
    }
}

#endif

<|start_filename|>Runtime/Manager/IManager.cs<|end_filename|>
using System;

namespace Framework
{
    public interface IManager
    {
        void Init();
        void Start();
        void CheckType(Type type);
    }
    
    public class ClassData
    {
        public ManagerAttribute Attribute;
        public Type Type;
    }
}

<|start_filename|>Runtime/UI/Wrap/ToggleWrapper.cs<|end_filename|>
﻿using System;
using Framework.UI.Core;
using Framework.UI.Wrap.Base;
using UnityEngine.Events;
using UnityEngine.UI;

namespace Framework.UI.Wrap
{
    public class ToggleWrapper : BaseWrapper<Toggle>, IFieldChangeCb<bool>, IComponentEvent<bool>
    {
        Action<bool> IFieldChangeCb<bool>.GetFieldChangeCb()
        {
            return (value) => Component.isOn = value;
        }

        UnityEvent<bool> IComponentEvent<bool>.GetComponentEvent()
        {
            return Component.onValueChanged;
        }

        public ToggleWrapper(Toggle component, View view) : base(component, view)
        {
        }
    }
}

<|start_filename|>Runtime/UI/Wrap/DefaultWrapper.cs<|end_filename|>
using Framework.UI.Wrap.Base;

namespace Framework.UI.Wrap
{
    public class DefaultWrapper : BaseWrapper<object>
    {
        public DefaultWrapper(object component, object container) : base(component, container)
        {
        }
    }
}

<|start_filename|>Runtime/Common/Pool/IPool.cs<|end_filename|>
using System;
using Framework.Asynchronous;

namespace Framework.Pool
{
	public interface IPool<T> : IDisposable
	{
        T Allocate();

        void Free(T obj);
	}
	
	public interface IPoolWithKey<TKey,T> : IDisposable
	{
		T Allocate(TKey key);

		void Free(TKey key, T obj);
	}

	public interface IAsyncPool<T> : IDisposable
	{
		AsyncResult<T> Allocate();
		void Free(T obj);
	}
}


<|start_filename|>Runtime/UI/Core/UIAttribute.cs<|end_filename|>
using System;

namespace Framework.UI.Core
{
    public class UIAttribute : ManagerAttribute
    {
        public string Path { get; private set; }

        public UIAttribute(string path) : base(-1)
        {
            Path = path;
        }
    }
}

<|start_filename|>Runtime/Common/Config/ConfigBase.cs<|end_filename|>
﻿using System.Collections.Generic;
using System.IO;
using UnityEngine;

namespace Framework
{
    public class ConfigBase : ScriptableObject
    {
        private static List<ScriptableObject> _configs = new List<ScriptableObject>();
        
        public static T Load<T>() where T : ScriptableObject
        {
            foreach (var conf in _configs)
            {
                if (conf is T result)
                    return result;
            }
            var path = $"Config/{typeof(T).Name}";
            T config = Resources.Load(path,typeof(T)) as T;
#if UNITY_EDITOR
            if (config == null)
            {
                Directory.CreateDirectory($"{FApplication.AssetsRoot}/Resources/Config");
                config = CreateInstance(typeof(T)) as T;
                UnityEditor.AssetDatabase.CreateAsset(config, "Assets/Resources/" + path + ".asset");
                UnityEditor.AssetDatabase.SaveAssets();
                UnityEditor.AssetDatabase.Refresh();
            }
#endif
            _configs.Add(config);
            return config;
        }
    }
}

<|start_filename|>Plugins/IngameDebugConsole/Scripts/CommandButton.cs<|end_filename|>
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

namespace IngameDebugConsole
{
    public class CommandButton : MonoBehaviour
    {
        [SerializeField]
        private Button Btn;

        [SerializeField]
        private InputField Input;

        [SerializeField]
        private Text NameTxt;

        [SerializeField] 
        private Text DescTxt;

        private Image btnImg;
        private string oldName;

        private void Start()
        {
            btnImg = Btn.GetComponent<Image>();
        }

        public void Init(ConsoleMethodInfo consoleMethodInfo)
        {
            Input.placeholder.GetComponent<Text>().text = "请输入参数，类型在上面，每个参数用空格分隔";
            Input.gameObject.SetActive(consoleMethodInfo.parameterTypes.Length > 0);
            oldName = $">{consoleMethodInfo.command}({string.Join("",consoleMethodInfo.parameters)})";
            NameTxt.text = oldName;
            DescTxt.text = consoleMethodInfo.description;
            Btn.onClick.AddListener(() =>
            {
                DebugLogConsole.ExecuteCommand($"{consoleMethodInfo.command} {Input.text}");
                btnImg.color = Color.green;
                NameTxt.text = "执行成功！！";
                StartCoroutine(Delay(1, () =>
                {
                    btnImg.color = Color.white;
                    NameTxt.text = oldName;
                }));
            });
        }

        IEnumerator Delay(float time, Action action)
        {
            yield return new WaitForSeconds(time);
            action();
        }
    }
}

<|start_filename|>Runtime/Tool/LitJsonHelper.cs<|end_filename|>
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using LitJson;
using UnityEngine;

namespace Framework.Helper
{
    public static class LitJsonHelper
    {
        public static string GetMD5(string str)
        {
            byte[] bytes = Encoding.UTF8.GetBytes(str);
            return GetMD5(bytes);
        }
        
        public static void WriteProperty(this JsonWriter w,string name,long value){
            w.WritePropertyName(name);
            w.Write(value);
        }

        public static void WriteProperty(this JsonWriter w,string name,string value){
            w.WritePropertyName(name);
            w.Write(value);
        }

        public static void WriteProperty(this JsonWriter w,string name,bool value){
            w.WritePropertyName(name);
            w.Write(value);
        }

        public static void WriteProperty(this JsonWriter w,string name,double value){
            w.WritePropertyName(name);
            w.Write(value);
        }

        public static string GetMD5(byte[] bytes)
        {
            MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
            byte[] retBytes = md5.ComputeHash(bytes);
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < retBytes.Length; i++)
            {
                sb.AppendFormat("{0:x2}", retBytes[i]);
            }

            return sb.ToString();
        }

        public static string GetBase64(string str)
        {
            byte[] bytes = Encoding.UTF8.GetBytes(str);
            return Convert.ToBase64String(bytes);
        }

        #region Json Help

        public static string GetJsonStrField(this JsonData data, string field)
        {
            if (data.HasField(field))
            {
                IJsonWrapper strData = (IJsonWrapper) data[field];
                return strData.GetString();
            }

            return null;
        }

        public static string GetJsonString(this JsonData data)
        {
            return ((IJsonWrapper) data).GetString();
        }

        public static void SetJsonString(this JsonData data, string val)
        {
            ((IJsonWrapper) data).SetString(val);
        }

        public static int GetJsonInt(this JsonData data)
        {
            return ((IJsonWrapper) data).GetInt();
        }

        public static void SetJsonInt(this JsonData data, int val)
        {
            ((IJsonWrapper) data).SetInt(val);
        }

        public static bool GetJsonBool(this JsonData data)
        {
            return ((IJsonWrapper) data).GetBoolean();
        }

        public static void SetJsonBool(this JsonData data, bool val)
        {
            ((IJsonWrapper) data).SetBoolean(val);
        }

        public static long GetJsonLong(this JsonData data)
        {
            return ((IJsonWrapper) data).GetLong();
        }

        public static double GetJsonDouble(this JsonData data)
        {
            IJsonWrapper id = data;
            if (id.IsInt)
                return id.GetInt();
            else if (id.IsLong)
                return id.GetLong();
            return id.GetDouble();
        }

        public static float GetJsonFloat(this JsonData data)
        {
            return Convert.ToSingle(GetJsonDouble(data));
        }

        public static void SetJsonFloat(this JsonData data, float val)
        {
            ((IJsonWrapper) data).SetDouble(val);
        }

        public static bool HasField(this JsonData data, string key)
        {
            return ((IDictionary) data).Contains(key);
        }

        public static void AddField(this JsonData data, string key, object val)
        {
            ((IDictionary) data).Add(key, val);
        }

        public static void RemoveField(this JsonData data, string key)
        {
            ((IDictionary) data).Remove(key);
        }

        public static string ToFormatJson(this JsonData data)
        {
            StringWriter sw = new StringWriter();
            JsonWriter writer = new JsonWriter(sw);
            writer.Validate = false;
            writer.PrettyPrint = true;
            data.ToJson(writer);
            return sw.ToString();
        }

        #endregion

        #region RegisterUnityType
        
        static bool registerd;

        public static void Register()
        {

            if (registerd) return;
            registerd = true;


            // 注册Type类型的Exporter
            JsonMapper.RegisterExporter<Type>((v, w) =>
            {
                w.Write(v.FullName);
            });

            JsonMapper.RegisterImporter<string, Type>((s) =>
            {
                return Type.GetType(s);
            });

            // 注册Vector2类型的Exporter
            Action<Vector2, JsonWriter> writeVector2 = (v, w) =>
            {
                w.WriteObjectStart();
                w.WriteProperty("x", v.x);
                w.WriteProperty("y", v.y);
                w.WriteObjectEnd();
            };

            JsonMapper.RegisterExporter<Vector2>((v, w) =>
            {
                writeVector2(v, w);
            });

            // 注册Vector3类型的Exporter
            Action<Vector3, JsonWriter> writeVector3 = (v, w) =>
            {
                w.WriteObjectStart();
                w.WriteProperty("x", v.x);
                w.WriteProperty("y", v.y);
                w.WriteProperty("z", v.z);
                w.WriteObjectEnd();
            };

            JsonMapper.RegisterExporter<Vector3>((v, w) =>
            {
                writeVector3(v, w);
            });

            // 注册Vector4类型的Exporter
            JsonMapper.RegisterExporter<Vector4>((v, w) =>
            {
                w.WriteObjectStart();
                w.WriteProperty("x", v.x);
                w.WriteProperty("y", v.y);
                w.WriteProperty("z", v.z);
                w.WriteProperty("w", v.w);
                w.WriteObjectEnd();
            });

            // 注册Quaternion类型的Exporter
            JsonMapper.RegisterExporter<Quaternion>((v, w) =>
            {
                w.WriteObjectStart();
                w.WriteProperty("x", v.x);
                w.WriteProperty("y", v.y);
                w.WriteProperty("z", v.z);
                w.WriteProperty("w", v.w);
                w.WriteObjectEnd();
            });

            // 注册Color类型的Exporter
            JsonMapper.RegisterExporter<Color>((v, w) =>
            {
                w.WriteObjectStart();
                w.WriteProperty("r", v.r);
                w.WriteProperty("g", v.g);
                w.WriteProperty("b", v.b);
                w.WriteProperty("a", v.a);
                w.WriteObjectEnd();
            });

            // 注册Color32类型的Exporter
            JsonMapper.RegisterExporter<Color32>((v, w) =>
            {
                w.WriteObjectStart();
                w.WriteProperty("r", v.r);
                w.WriteProperty("g", v.g);
                w.WriteProperty("b", v.b);
                w.WriteProperty("a", v.a);
                w.WriteObjectEnd();
            });

            // 注册Bounds类型的Exporter
            JsonMapper.RegisterExporter<Bounds>((v, w) =>
            {
                w.WriteObjectStart();

                w.WritePropertyName("center");
                writeVector3(v.center, w);

                w.WritePropertyName("size");
                writeVector3(v.size, w);

                w.WriteObjectEnd();
            });

            // 注册Rect类型的Exporter
            JsonMapper.RegisterExporter<Rect>((v, w) =>
            {
                w.WriteObjectStart();
                w.WriteProperty("x", v.x);
                w.WriteProperty("y", v.y);
                w.WriteProperty("width", v.width);
                w.WriteProperty("height", v.height);
                w.WriteObjectEnd();
            });

            // 注册RectOffset类型的Exporter
            JsonMapper.RegisterExporter<RectOffset>((v, w) =>
            {
                w.WriteObjectStart();
                w.WriteProperty("top", v.top);
                w.WriteProperty("left", v.left);
                w.WriteProperty("bottom", v.bottom);
                w.WriteProperty("right", v.right);
                w.WriteObjectEnd();
            });
        }
        
        #endregion
    }
}

<|start_filename|>Runtime/UI/Core/Animation/IAnimation.cs<|end_filename|>
using System;

namespace Framework.UI.Core
{
    public interface IAnimation
    {
        IAnimation OnStart(Action onStart);

        IAnimation OnEnd(Action onEnd);

        IAnimation Play();

    }
}

<|start_filename|>Runtime/UI/Wrap/ButtonWrapper.cs<|end_filename|>
﻿using System;
using Framework.UI.Core;
using Framework.UI.Wrap.Base;
using TMPro;
using UnityEngine.Events;
using UnityEngine.UI;

namespace Framework.UI.Wrap
{
    public class ButtonWrapper : BaseWrapper<Button>, IComponentEvent , IFieldChangeCb<string> , IFieldChangeCb<int> , IFieldChangeCb<float> , IFieldChangeCb<long> , IFieldChangeCb<double>
    {
        private Text text;
        private TextMeshProUGUI tmpText;
        UnityEvent IComponentEvent.GetComponentEvent()
        {
            return Component.onClick;
        }

        public ButtonWrapper(Button component, View view) : base(component, view)
        {
            text = component.GetComponentInChildren<Text>();
            tmpText = component.GetComponentInChildren<TextMeshProUGUI>();
        }

        public Action<string> GetFieldChangeCb()
        {
            return val =>
            {
                if (text)
                    text.text = val;
                if (tmpText)
                    tmpText.text = val;
            };
        }

        Action<int> IFieldChangeCb<int>.GetFieldChangeCb()
        {
            return val =>
            {
                if (text)
                    text.text = val.ToString();
                if (tmpText)
                    tmpText.text = val.ToString();
            };
        }

        Action<float> IFieldChangeCb<float>.GetFieldChangeCb()
        {
            return val =>
            {
                if (text)
                    text.text = val.ToString();
                if (tmpText)
                    tmpText.text = val.ToString();
            };
        }

        Action<long> IFieldChangeCb<long>.GetFieldChangeCb()
        {
            return val =>
            {
                if (text)
                    text.text = val.ToString();
                if (tmpText)
                    tmpText.text = val.ToString();
            };
        }

        Action<double> IFieldChangeCb<double>.GetFieldChangeCb()
        {
            return val =>
            {
                if (text)
                    text.text = val.ToString();
                if (tmpText)
                    tmpText.text = val.ToString();
            };
        }
    }
}

<|start_filename|>Editor/EditorIcons.cs<|end_filename|>
﻿
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.Linq;

namespace Framework.Editor
{

    public class EditorIcons : EditorWindow
    {
        [MenuItem("Framework/Tool/Editor Icons", priority = -1001)]
        public static void EditorIconsOpen()
        {
            var w = CreateWindow<EditorIcons>("Editor Icons");
            w.ShowUtility();
            w.minSize = new Vector2(320, 450);
        }

        static bool viewBigIcons = true;

        static bool darkPreview = true;

        Vector2 scroll;

        int buttonSize = 70;

        string search = "";

        void SearchGUI()
        {
            using (new GUILayout.HorizontalScope())
            {
                if (isWide) GUILayout.Space(10);

                search = EditorGUILayout.TextField(search, EditorStyles.toolbarSearchField);
                if (GUILayout.Button(EditorGUIUtility.IconContent("winbtn_mac_close_h"), //SVN_DeletedLocal
                    EditorStyles.toolbarButton,
                    GUILayout.Width(22))
                ) search = "";
            }
        }

        bool isWide => Screen.width > 550;

        bool doSearch => !string.IsNullOrWhiteSpace(search) && search != "";

        GUIContent GetIcon(string icon_name)
        {
            GUIContent valid = null;
            Debug.unityLogger.logEnabled = false;
            if (!string.IsNullOrEmpty(icon_name)) valid = EditorGUIUtility.IconContent(icon_name);
            Debug.unityLogger.logEnabled = true;
            return valid?.image == null ? null : valid;
        }

        private void OnEnable()
        {
            //InitIcons();
            //var all_icons = iconContentListAll.Select(x => x.tooltip).ToArray();
            var all_icons = ico_list.Where(x => GetIcon(x) != null);
            //List<string> found = new List<string>();
            List<string> unique = new List<string>();
            //var skip_flag = HideFlags.HideInInspector | HideFlags.HideAndDontSave;
            //int unique_to_resources = 0, skipped_empty_str = 0, skipped_flags = 0, 
            //    skipped_not_persistent = 0, skipped_nulls = 0, unique_to_list = 0;

            foreach (Texture2D x in Resources.FindObjectsOfTypeAll<Texture2D>())
            {
                //if (string.IsNullOrEmpty(x.name)) skipped_empty_str++;                                      // skipped 10 empty
                //if (!EditorUtility.IsPersistent(x)) skipped_not_persistent++;                               // skipped 39 none persistent
                //if (x.hideFlags != HideFlags.HideAndDontSave && x.hideFlags != skip_flag) skipped_flags++;  // skipped 27 icons

                GUIContent icoContent = GetIcon(x.name);
                if (icoContent == null) continue; // skipped 14 icons 
                //{ 
                //    skipped_nulls++; 
                //    continue; 
                //}

                if (!all_icons.Contains(x.name))
                {
                    //unique_to_resources++;
                    unique.Add(x.name);
                }

                //found.Add( x.name );
            }

            //foreach (var ico in all_icons) if (!found.Contains(ico)) unique_to_list++;

            //Debug.Log( $"Resources skipped nulls={skipped_nulls} empty={skipped_empty_str} flags={skipped_flags}" );
            //Debug.Log("Resources skipped_not_persistent=" + skipped_not_persistent);
            //Debug.Log($"totals , list: {all_icons.Length} resource: {found.Count}");
            //Debug.Log($"Unique list={ unique_to_list } resources={unique_to_resources}") ;

            ico_list = ico_list.ToList().Concat(unique).ToArray();

            // Static list icons count : 1315 ( unique = 749 )
            // Found icons in resources : 1416 ( unique = 855 )

            Resources.UnloadUnusedAssets();
            System.GC.Collect();
        }

        private void OnGUI()
        {
            var ppp = EditorGUIUtility.pixelsPerPoint;

            InitIcons();

            if (!isWide) SearchGUI();

            using (new GUILayout.HorizontalScope(EditorStyles.toolbar))
            {
                GUILayout.Label("Select what icons to show", GUILayout.Width(160));
                viewBigIcons = GUILayout.SelectionGrid(
                    viewBigIcons ? 1 : 0, new string[] {"Small", "Big"},
                    2, EditorStyles.toolbarButton) == 1;

                if (isWide) SearchGUI();
            }

            if (isWide) GUILayout.Space(3);

            using (var scope = new GUILayout.ScrollViewScope(scroll))
            {
                GUILayout.Space(10);

                scroll = scope.scrollPosition;

                buttonSize = viewBigIcons ? 70 : 40;

                // scrollbar_width = ~ 12.5
                var render_width = (Screen.width / ppp - 13f);
                var gridW = Mathf.FloorToInt(render_width / buttonSize);
                var margin_left = (render_width - buttonSize * gridW) / 2;

                int row = 0, index = 0;

                List<GUIContent> iconList;

                if (doSearch)
                    iconList = iconContentListAll.Where(x => x.tooltip.ToLower()
                        .Contains(search.ToLower())).ToList();
                else iconList = viewBigIcons ? iconContentListBig : iconContentListSmall;

                while (index < iconList.Count)
                {
                    using (new GUILayout.HorizontalScope())
                    {
                        GUILayout.Space(margin_left);

                        for (var i = 0; i < gridW; ++i)
                        {
                            int k = i + row * gridW;

                            var icon = iconList[k];

                            if (GUILayout.Button(icon,
                                iconButtonStyle,
                                GUILayout.Width(buttonSize),
                                GUILayout.Height(buttonSize)))
                            {
                                EditorGUI.FocusTextInControl("");
                                iconSelected = icon;
                            }

                            index++;

                            if (index == iconList.Count) break;
                        }
                    }

                    row++;
                }

                GUILayout.Space(10);
            }


            if (iconSelected == null) return;

            GUILayout.FlexibleSpace();

            using (new GUILayout.HorizontalScope(EditorStyles.helpBox, GUILayout.MaxHeight(viewBigIcons ? 140 : 120)))
            {
                using (new GUILayout.VerticalScope(GUILayout.Width(130)))
                {
                    GUILayout.Space(2);

                    GUILayout.Button(iconSelected,
                        darkPreview ? iconPreviewBlack : iconPreviewWhite,
                        GUILayout.Width(128), GUILayout.Height(viewBigIcons ? 128 : 40));

                    GUILayout.Space(5);

                    darkPreview = GUILayout.SelectionGrid(
                        darkPreview ? 1 : 0, new string[] {"Light", "Dark"},
                        2, EditorStyles.miniButton) == 1;

                    GUILayout.FlexibleSpace();
                }

                GUILayout.Space(10);

                using (new GUILayout.VerticalScope())
                {
                    var s = $"Size: {iconSelected.image.width}x{iconSelected.image.height}";
                    s += "\nIs Pro Skin Icon: " + (iconSelected.tooltip.IndexOf("d_") == 0 ? "Yes" : "No");
                    s += $"\nTotal {iconContentListAll.Count} icons";
                    GUILayout.Space(5);
                    EditorGUILayout.HelpBox(s, MessageType.None);
                    GUILayout.Space(5);
                    EditorGUILayout.TextField("EditorGUIUtility.IconContent(\"" + iconSelected.tooltip + "\")");
                    GUILayout.Space(5);
                    if (GUILayout.Button("Copy to clipboard", EditorStyles.miniButton))
                        EditorGUIUtility.systemCopyBuffer = iconSelected.tooltip;
                }

                GUILayout.Space(10);

                if (GUILayout.Button("X", GUILayout.ExpandHeight(true)))
                {
                    iconSelected = null;
                }

            }
        }

        static GUIContent iconSelected;
        static List<GUIContent> iconContentListAll;
        static List<GUIContent> iconContentListSmall;
        static List<GUIContent> iconContentListBig;
        static GUIStyle iconButtonStyle = null;
        static GUIStyle iconPreviewBlack = null;
        static GUIStyle iconPreviewWhite = null;

        void AllTheTEXTURES(ref GUIStyle s, Texture2D t)
        {
            s.hover.background = s.onHover.background = s.focused.background = s.onFocused.background =
                s.active.background = s.onActive.background = s.normal.background = s.onNormal.background = t;
            s.hover.scaledBackgrounds = s.onHover.scaledBackgrounds = s.focused.scaledBackgrounds =
                s.onFocused.scaledBackgrounds = s.active.scaledBackgrounds = s.onActive.scaledBackgrounds =
                    s.normal.scaledBackgrounds = s.onNormal.scaledBackgrounds = new Texture2D[] {t};
        }

        Texture2D Texture2DPixel(Color c)
        {
            Texture2D t = new Texture2D(1, 1);
            t.SetPixel(0, 0, c);
            t.Apply();
            return t;
        }

        void InitIcons()
        {
            if (iconContentListSmall != null) return;

            iconButtonStyle = new GUIStyle(EditorStyles.miniButton);
            iconButtonStyle.margin = new RectOffset(0, 0, 0, 0);
            iconButtonStyle.fixedHeight = 0;

            iconPreviewBlack = new GUIStyle(iconButtonStyle);
            AllTheTEXTURES(ref iconPreviewBlack, Texture2DPixel(new Color(0.15f, 0.15f, 0.15f)));

            iconPreviewWhite = new GUIStyle(iconButtonStyle);
            AllTheTEXTURES(ref iconPreviewWhite, Texture2DPixel(new Color(0.85f, 0.85f, 0.85f)));

            iconContentListSmall = new List<GUIContent>();
            iconContentListBig = new List<GUIContent>();
            iconContentListAll = new List<GUIContent>();

            for (var i = 0; i < ico_list.Length; ++i)
            {
                GUIContent ico = GetIcon(ico_list[i]);

                if (ico == null)
                {
                    continue;
                }

                ico.tooltip = ico_list[i];

                iconContentListAll.Add(ico);

                if (!(ico.image.width <= 36 || ico.image.height <= 36))
                    iconContentListBig.Add(ico);
                else iconContentListSmall.Add(ico);
            }
        }

        // https://gist.github.com/MattRix/c1f7840ae2419d8eb2ec0695448d4321
        // https://unitylist.com/p/5c3/Unity-editor-icons

        #region ICONS

        public static string[] ico_list =
        {
            "_Help", "_Popup", "aboutwindow.mainheader", "ageialogo", "AlphabeticalSorting", "Animation.AddEvent",
            "Animation.AddKeyframe", "Animation.EventMarker", "Animation.FirstKey", "Animation.LastKey",
            "Animation.NextKey", "Animation.Play", "Animation.PrevKey", "Animation.Record", "Animation.SequencerLink",
            "animationanimated", "animationdopesheetkeyframe", "animationkeyframe", "animationnocurve",
            "animationvisibilitytoggleoff", "animationvisibilitytoggleon", "AnimationWrapModeMenu", "AssemblyLock",
            "Asset Store", "Audio Mixer", "AvatarCompass", "AvatarController.Layer", "AvatarController.LayerHover",
            "AvatarController.LayerSelected", "BodyPartPicker", "BodySilhouette", "DotFill", "DotFrame",
            "DotFrameDotted",
            "DotSelection", "Head", "HeadIk", "HeadZoom", "HeadZoomSilhouette", "LeftArm", "LeftFeetIk", "LeftFingers",
            "LeftFingersIk", "LeftHandZoom", "LeftHandZoomSilhouette", "LeftLeg", "MaskEditor_Root", "RightArm",
            "RightFeetIk",
            "RightFingers", "RightFingersIk", "RightHandZoom", "RightHandZoomSilhouette", "RightLeg", "Torso",
            "AvatarPivot",
            "back", "back@2x", "beginButton-On", "beginButton", "blendKey", "blendKeyOverlay", "blendKeySelected",
            "blendSampler", "blueGroove", "BuildSettings.Android", "BuildSettings.Android.Small",
            "BuildSettings.Broadcom",
            "BuildSettings.Editor", "BuildSettings.Editor.Small", "BuildSettings.Facebook",
            "BuildSettings.Facebook.Small", "BuildSettings.FlashPlayer", "BuildSettings.FlashPlayer.Small",
            "BuildSettings.iPhone", "BuildSettings.iPhone.Small", "BuildSettings.Lumin", "BuildSettings.Lumin.small",
            "BuildSettings.Metro", "BuildSettings.Metro.Small", "BuildSettings.N3DS", "BuildSettings.N3DS.Small",
            "BuildSettings.PS4", "BuildSettings.PS4.Small", "BuildSettings.PSM", "BuildSettings.PSM.Small",
            "BuildSettings.PSP2", "BuildSettings.PSP2.Small", "BuildSettings.SelectedIcon", "BuildSettings.Standalone",
            "BuildSettings.Standalone.Small", "BuildSettings.StandaloneBroadcom.Small",
            "BuildSettings.StandaloneGLES20Emu.Small", "BuildSettings.StandaloneGLESEmu",
            "BuildSettings.StandaloneGLESEmu.Small", "BuildSettings.Switch", "BuildSettings.Switch.Small",
            "BuildSettings.tvOS", "BuildSettings.tvOS.Small", "BuildSettings.Web", "BuildSettings.Web.Small",
            "BuildSettings.WebGL", "BuildSettings.WebGL.Small", "BuildSettings.WP8", "BuildSettings.WP8.Small",
            "BuildSettings.Xbox360", "BuildSettings.Xbox360.Small", "BuildSettings.XboxOne",
            "BuildSettings.XboxOne.Small", "BuildSettings.Xiaomi", "Camera Gizmo", "CheckerFloor", "Clipboard",
            "ClothInspector.PaintTool", "ClothInspector.PaintValue", "ClothInspector.SelectTool",
            "ClothInspector.SettingsTool", "ClothInspector.ViewValue", "CloudConnect", "Collab.Build",
            "Collab.BuildFailed", "Collab.BuildSucceeded", "Collab.FileAdded", "Collab.FileConflict",
            "Collab.FileDeleted",
            "Collab.FileIgnored", "Collab.FileMoved", "Collab.FileUpdated", "Collab.FolderAdded",
            "Collab.FolderConflict",
            "Collab.FolderDeleted", "Collab.FolderIgnored", "Collab.FolderMoved", "Collab.FolderUpdated",
            "Collab.NoInternet", "Collab", "Collab.Warning", "CollabConflict", "CollabError", "CollabNew",
            "CollabOffline",
            "CollabProgress", "CollabPull", "CollabPush", "ColorPicker.ColorCycle", "ColorPicker.CycleColor",
            "ColorPicker.CycleSlider", "ColorPicker.SliderCycle", "console.erroricon.inactive.sml", "console.erroricon",
            "console.erroricon.sml", "console.infoicon", "console.infoicon.sml", "console.warnicon.inactive.sml",
            "console.warnicon", "console.warnicon.sml", "curvekeyframe", "curvekeyframeselected",
            "curvekeyframeselectedoverlay", "curvekeyframesemiselectedoverlay", "curvekeyframeweighted",
            "CustomSorting",
            "d__Popup", "d_aboutwindow.mainheader", "d_ageialogo", "d_AlphabeticalSorting", "d_Animation.AddEvent",
            "d_Animation.AddKeyframe", "d_Animation.EventMarker", "d_Animation.FirstKey", "d_Animation.LastKey",
            "d_Animation.NextKey", "d_Animation.Play", "d_Animation.PrevKey", "d_Animation.Record",
            "d_Animation.SequencerLink", "d_animationanimated", "d_animationkeyframe", "d_animationnocurve",
            "d_animationvisibilitytoggleoff", "d_animationvisibilitytoggleon", "d_AnimationWrapModeMenu",
            "d_AS Badge Delete", "d_AS Badge New", "d_AssemblyLock", "d_Asset Store", "d_Audio Mixer",
            "d_AvatarBlendBackground", "d_AvatarBlendLeft", "d_AvatarBlendLeftA", "d_AvatarBlendRight",
            "d_AvatarBlendRightA", "d_AvatarCompass", "d_AvatarPivot", "d_back", "d_back@2x", "d_beginButton-On",
            "d_beginButton", "d_blueGroove", "d_BuildSettings.Android", "d_BuildSettings.Android.Small",
            "d_BuildSettings.Broadcom", "d_BuildSettings.FlashPlayer", "d_BuildSettings.FlashPlayer.Small",
            "d_BuildSettings.iPhone", "d_BuildSettings.iPhone.Small", "d_BuildSettings.Lumin",
            "d_BuildSettings.Lumin.small", "d_BuildSettings.PS4", "d_BuildSettings.PS4.Small", "d_BuildSettings.PSP2",
            "d_BuildSettings.PSP2.Small", "d_BuildSettings.SelectedIcon", "d_BuildSettings.Standalone",
            "d_BuildSettings.Standalone.Small", "d_BuildSettings.tvOS", "d_BuildSettings.tvOS.Small",
            "d_BuildSettings.Web", "d_BuildSettings.Web.Small", "d_BuildSettings.WebGL", "d_BuildSettings.WebGL.Small",
            "d_BuildSettings.Xbox360", "d_BuildSettings.Xbox360.Small", "d_BuildSettings.XboxOne",
            "d_BuildSettings.XboxOne.Small", "d_CheckerFloor", "d_CloudConnect", "d_Collab.FileAdded",
            "d_Collab.FileConflict", "d_Collab.FileDeleted", "d_Collab.FileIgnored", "d_Collab.FileMoved",
            "d_Collab.FileUpdated", "d_Collab.FolderAdded", "d_Collab.FolderConflict", "d_Collab.FolderDeleted",
            "d_Collab.FolderIgnored", "d_Collab.FolderMoved", "d_Collab.FolderUpdated", "d_ColorPicker.CycleColor",
            "d_ColorPicker.CycleSlider", "d_console.erroricon", "d_console.erroricon.sml", "d_console.infoicon",
            "d_console.infoicon.sml", "d_console.warnicon", "d_console.warnicon.sml", "d_curvekeyframe",
            "d_curvekeyframeselected", "d_curvekeyframeselectedoverlay", "d_curvekeyframesemiselectedoverlay",
            "d_curvekeyframeweighted", "d_CustomSorting", "d_DefaultSorting", "d_EditCollider", "d_editcollision_16",
            "d_editconstraints_16", "d_editicon.sml", "d_endButton-On", "d_endButton", "d_eyeDropper.Large",
            "d_eyeDropper.sml", "d_Favorite", "d_FilterByLabel", "d_FilterByType", "d_FilterSelectedOnly",
            "d_FilterSelectedOnly@2x", "d_forward", "d_forward@2x", "d_GEAR", "d_Groove", "d_HorizontalSplit",
            "d_icon dropdown", "d_InspectorLock", "d_JointAngularLimits", "d_leftBracket", "d_Lighting",
            "d_LightmapEditor.WindowTitle", "d_LookDevCenterLight", "d_LookDevCenterLight@2x", "d_LookDevClose",
            "d_LookDevClose@2x", "d_LookDevEnvRotation", "d_LookDevEnvRotation@2x", "d_LookDevMirrorViews",
            "d_LookDevMirrorViews@2x", "d_LookDevMirrorViewsActive", "d_LookDevMirrorViewsActive@2x",
            "d_LookDevMirrorViewsInactive", "d_LookDevMirrorViewsInactive@2x", "d_LookDevObjRotation",
            "d_LookDevObjRotation@2x", "d_LookDevPaneOption", "d_LookDevPaneOption@2x", "d_LookDevResetEnv",
            "d_LookDevResetEnv@2x", "d_LookDevShadow", "d_LookDevShadow@2x", "d_LookDevSideBySide",
            "d_LookDevSideBySide@2x", "d_LookDevSingle1", "d_LookDevSingle1@2x", "d_LookDevSingle2",
            "d_LookDevSingle2@2x", "d_LookDevSplit", "d_LookDevSplit@2x", "d_LookDevZone", "d_LookDevZone@2x",
            "d_Mirror", "d_model large", "d_monologo", "d_MoveTool on", "d_MoveTool", "d_Navigation", "d_Occlusion",
            "d_P4_AddedLocal", "d_P4_AddedRemote", "d_P4_CheckOutLocal", "d_P4_CheckOutRemote", "d_P4_Conflicted",
            "d_P4_DeletedLocal", "d_P4_DeletedRemote", "d_P4_Local", "d_P4_LockedLocal", "d_P4_LockedRemote",
            "d_P4_OutOfSync", "d_Particle Effect", "d_PauseButton On", "d_PauseButton", "d_PlayButton On",
            "d_PlayButton",
            "d_PlayButtonProfile On", "d_PlayButtonProfile", "d_playLoopOff", "d_playLoopOn", "d_preAudioAutoPlayOff",
            "d_preAudioAutoPlayOn", "d_preAudioLoopOff", "d_preAudioLoopOn", "d_preAudioPlayOff", "d_preAudioPlayOn",
            "d_PreMatCube", "d_PreMatCylinder", "d_PreMatLight0", "d_PreMatLight1", "d_PreMatSphere", "d_PreMatTorus",
            "d_Preset.Context", "d_PreTextureAlpha", "d_PreTextureMipMapHigh", "d_PreTextureMipMapLow",
            "d_PreTextureRGB",
            "d_Profiler.Audio", "d_Profiler.CPU", "d_Profiler.FirstFrame", "d_Profiler.GPU", "d_Profiler.LastFrame",
            "d_Profiler.Memory", "d_Profiler.Network", "d_Profiler.NextFrame", "d_Profiler.Physics",
            "d_Profiler.PrevFrame",
            "d_Profiler.Record", "d_Profiler.Rendering", "d_Profiler.Video", "d_ProfilerColumn.WarningCount",
            "d_Project",
            "d_RectTool On", "d_RectTool", "d_RectTransformBlueprint", "d_RectTransformRaw", "d_redGroove", "d_Refresh",
            "d_renderdoc", "d_rightBracket", "d_RotateTool On", "d_RotateTool", "d_ScaleTool On", "d_ScaleTool",
            "d_SceneViewAlpha", "d_SceneViewAudio", "d_SceneViewFx", "d_SceneViewLighting", "d_SceneViewOrtho",
            "d_SceneViewRGB", "d_ScrollShadow", "d_Settings", "d_SettingsIcon", "d_SocialNetworks.FacebookShare",
            "d_SocialNetworks.LinkedInShare", "d_SocialNetworks.Tweet", "d_SocialNetworks.UDNOpen", "d_SpeedScale",
            "d_StepButton On", "d_StepButton", "d_StepLeftButton-On", "d_StepLeftButton", "d_SVN_AddedLocal",
            "d_SVN_Conflicted", "d_SVN_DeletedLocal", "d_SVN_Local", "d_SVN_LockedLocal", "d_SVN_OutOfSync",
            "d_tab_next",
            "d_tab_next@2x", "d_tab_prev", "d_tab_prev@2x", "d_TerrainInspector.TerrainToolLower On",
            "d_TerrainInspector.TerrainToolLowerAlt", "d_TerrainInspector.TerrainToolPlants On",
            "d_TerrainInspector.TerrainToolPlants", "d_TerrainInspector.TerrainToolPlantsAlt On",
            "d_TerrainInspector.TerrainToolPlantsAlt", "d_TerrainInspector.TerrainToolRaise On",
            "d_TerrainInspector.TerrainToolRaise", "d_TerrainInspector.TerrainToolSetheight On",
            "d_TerrainInspector.TerrainToolSetheight", "d_TerrainInspector.TerrainToolSetheightAlt On",
            "d_TerrainInspector.TerrainToolSetheightAlt", "d_TerrainInspector.TerrainToolSettings On",
            "d_TerrainInspector.TerrainToolSettings", "d_TerrainInspector.TerrainToolSmoothHeight On",
            "d_TerrainInspector.TerrainToolSmoothHeight", "d_TerrainInspector.TerrainToolSplat On",
            "d_TerrainInspector.TerrainToolSplat", "d_TerrainInspector.TerrainToolSplatAlt On",
            "d_TerrainInspector.TerrainToolSplatAlt", "d_TerrainInspector.TerrainToolTrees On",
            "d_TerrainInspector.TerrainToolTrees", "d_TerrainInspector.TerrainToolTreesAlt On",
            "d_TerrainInspector.TerrainToolTreesAlt", "d_TimelineDigIn", "d_TimelineEditModeMixOFF",
            "d_TimelineEditModeMixON", "d_TimelineEditModeReplaceOFF", "d_TimelineEditModeReplaceON",
            "d_TimelineEditModeRippleOFF", "d_TimelineEditModeRippleON", "d_TimelineSelector", "d_Toolbar Minus",
            "d_Toolbar Plus More", "d_Toolbar Plus", "d_ToolHandleCenter", "d_ToolHandleGlobal", "d_ToolHandleLocal",
            "d_ToolHandlePivot", "d_tranp", "d_TransformTool On", "d_TransformTool", "d_tree_icon",
            "d_tree_icon_branch",
            "d_tree_icon_branch_frond", "d_tree_icon_frond", "d_tree_icon_leaf", "d_TreeEditor.AddBranches",
            "d_TreeEditor.AddLeaves", "d_TreeEditor.Branch On", "d_TreeEditor.Branch", "d_TreeEditor.BranchFreeHand On",
            "d_TreeEditor.BranchFreeHand", "d_TreeEditor.BranchRotate On", "d_TreeEditor.BranchRotate",
            "d_TreeEditor.BranchScale On", "d_TreeEditor.BranchScale", "d_TreeEditor.BranchTranslate On",
            "d_TreeEditor.BranchTranslate", "d_TreeEditor.Distribution On", "d_TreeEditor.Distribution",
            "d_TreeEditor.Duplicate", "d_TreeEditor.Geometry On", "d_TreeEditor.Geometry", "d_TreeEditor.Leaf On",
            "d_TreeEditor.Leaf", "d_TreeEditor.LeafFreeHand On", "d_TreeEditor.LeafFreeHand",
            "d_TreeEditor.LeafRotate On",
            "d_TreeEditor.LeafRotate", "d_TreeEditor.LeafScale On", "d_TreeEditor.LeafScale",
            "d_TreeEditor.LeafTranslate On", "d_TreeEditor.LeafTranslate", "d_TreeEditor.Material On",
            "d_TreeEditor.Material", "d_TreeEditor.Refresh", "d_TreeEditor.Trash", "d_TreeEditor.Wind On",
            "d_TreeEditor.Wind", "d_UnityEditor.AnimationWindow", "d_UnityEditor.ConsoleWindow",
            "d_UnityEditor.DebugInspectorWindow", "d_UnityEditor.FindDependencies", "d_UnityEditor.GameView",
            "d_UnityEditor.HierarchyWindow", "d_UnityEditor.InspectorWindow", "d_UnityEditor.LookDevView",
            "d_UnityEditor.ProfilerWindow", "d_UnityEditor.SceneHierarchyWindow", "d_UnityEditor.SceneView",
            "d_UnityEditor.Timeline.TimelineWindow", "d_UnityEditor.VersionControl", "d_UnityLogo", "d_VerticalSplit",
            "d_ViewToolMove On", "d_ViewToolMove", "d_ViewToolOrbit On", "d_ViewToolOrbit", "d_ViewToolZoom On",
            "d_ViewToolZoom", "d_VisibilityOff", "d_VisibilityOn", "d_VUMeterTextureHorizontal",
            "d_VUMeterTextureVertical",
            "d_WaitSpin00", "d_WaitSpin01", "d_WaitSpin02", "d_WaitSpin03", "d_WaitSpin04", "d_WaitSpin05",
            "d_WaitSpin06",
            "d_WaitSpin07", "d_WaitSpin08", "d_WaitSpin09", "d_WaitSpin10", "d_WaitSpin11",
            "d_WelcomeScreen.AssetStoreLogo",
            "d_winbtn_graph", "d_winbtn_graph_close_h", "d_winbtn_graph_max_h", "d_winbtn_graph_min_h",
            "d_winbtn_mac_close", "d_winbtn_mac_close_a", "d_winbtn_mac_close_h", "d_winbtn_mac_inact",
            "d_winbtn_mac_max",
            "d_winbtn_mac_max_a", "d_winbtn_mac_max_h", "d_winbtn_mac_min", "d_winbtn_mac_min_a", "d_winbtn_mac_min_h",
            "d_winbtn_win_close", "d_winbtn_win_close_a", "d_winbtn_win_close_h", "d_winbtn_win_max",
            "d_winbtn_win_max_a",
            "d_winbtn_win_max_h", "d_winbtn_win_min", "d_winbtn_win_min_a", "d_winbtn_win_min_h", "d_winbtn_win_rest",
            "d_winbtn_win_rest_a", "d_winbtn_win_rest_h", "DefaultSorting", "EditCollider", "editcollision_16",
            "editconstraints_16", "editicon.sml", "endButton-On", "endButton", "eyeDropper.Large", "eyeDropper.sml",
            "Favorite", "FilterByLabel", "FilterByType", "FilterSelectedOnly", "FilterSelectedOnly@2x", "forward",
            "forward@2x", "GEAR", "Grid.BoxTool", "Grid.Default", "Grid.EraserTool", "Grid.FillTool", "Grid.MoveTool",
            "Grid.PaintTool", "Grid.PickingTool", "Grid.SelectTool", "Groove", "align_horizontally",
            "align_horizontally_center", "align_horizontally_center_active", "align_horizontally_left",
            "align_horizontally_left_active", "align_horizontally_right", "align_horizontally_right_active",
            "align_vertically", "align_vertically_bottom", "align_vertically_bottom_active", "align_vertically_center",
            "align_vertically_center_active", "align_vertically_top", "align_vertically_top_active",
            "d_align_horizontally", "d_align_horizontally_center", "d_align_horizontally_center_active",
            "d_align_horizontally_left", "d_align_horizontally_left_active", "d_align_horizontally_right",
            "d_align_horizontally_right_active", "d_align_vertically", "d_align_vertically_bottom",
            "d_align_vertically_bottom_active", "d_align_vertically_center", "d_align_vertically_center_active",
            "d_align_vertically_top", "d_align_vertically_top_active", "HorizontalSplit", "icon dropdown",
            "InspectorLock", "JointAngularLimits", "KnobCShape", "KnobCShapeMini", "leftBracket", "Lighting",
            "LightmapEditor.WindowTitle", "Lightmapping", "d_greenLight", "d_lightOff", "d_lightRim", "d_orangeLight",
            "d_redLight", "greenLight", "lightOff", "lightRim", "orangeLight", "redLight", "LockIcon-On", "LockIcon",
            "LookDevCenterLight", "LookDevCenterLightl@2x", "LookDevClose", "LookDevClose@2x", "LookDevEnvRotation",
            "LookDevEnvRotation@2x", "LookDevEyedrop", "LookDevLight", "LookDevLight@2x", "LookDevMirrorViewsActive",
            "LookDevMirrorViewsActive@2x", "LookDevMirrorViewsInactive", "LookDevMirrorViewsInactive@2x",
            "LookDevObjRotation", "LookDevObjRotation@2x", "LookDevPaneOption", "LookDevPaneOption@2x",
            "LookDevResetEnv",
            "LookDevResetEnv@2x", "LookDevShadow", "LookDevShadow@2x", "LookDevShadowFrame", "LookDevShadowFrame@2x",
            "LookDevSideBySide", "LookDevSideBySide@2x", "LookDevSingle1", "LookDevSingle1@2x", "LookDevSingle2",
            "LookDevSingle2@2x", "LookDevSplit", "LookDevSplit@2x", "LookDevZone", "LookDevZone@2x", "loop", "Mirror",
            "monologo", "MoveTool on", "MoveTool", "Navigation", "Occlusion", "P4_AddedLocal", "P4_AddedRemote",
            "P4_BlueLeftParenthesis", "P4_BlueRightParenthesis", "P4_CheckOutLocal", "P4_CheckOutRemote",
            "P4_Conflicted",
            "P4_DeletedLocal", "P4_DeletedRemote", "P4_Local", "P4_LockedLocal", "P4_LockedRemote", "P4_OutOfSync",
            "P4_RedLeftParenthesis", "P4_RedRightParenthesis", "P4_Updating", "PackageBadgeDelete", "PackageBadgeNew",
            "Particle Effect", "PauseButton On", "PauseButton", "PlayButton On", "PlayButton", "PlayButtonProfile On",
            "PlayButtonProfile", "playLoopOff", "playLoopOn", "playSpeed", "preAudioAutoPlayOff", "preAudioAutoPlayOn",
            "preAudioLoopOff", "preAudioLoopOn", "preAudioPlayOff", "preAudioPlayOn", "PreMatCube", "PreMatCylinder",
            "PreMatLight0", "PreMatLight1", "PreMatQuad", "PreMatSphere", "PreMatTorus", "Preset.Context",
            "PreTextureAlpha",
            "PreTextureArrayFirstSlice", "PreTextureArrayLastSlice", "PreTextureMipMapHigh", "PreTextureMipMapLow",
            "PreTextureRGB", "AreaLight Gizmo", "AreaLight Icon", "Assembly Icon", "AssetStore Icon",
            "AudioMixerView Icon",
            "AudioSource Gizmo", "Camera Gizmo", "CGProgram Icon", "ChorusFilter Icon", "CollabChanges Icon",
            "CollabChangesConflict Icon", "CollabChangesDeleted Icon", "CollabConflict Icon", "CollabCreate Icon",
            "CollabDeleted Icon", "CollabEdit Icon", "CollabExclude Icon", "CollabMoved Icon", "cs Script Icon",
            "d_AudioMixerView Icon", "d_CollabChanges Icon", "d_CollabChangesConflict Icon",
            "d_CollabChangesDeleted Icon",
            "d_CollabConflict Icon", "d_CollabCreate Icon", "d_CollabDeleted Icon", "d_CollabEdit Icon",
            "d_CollabExclude Icon", "d_CollabMoved Icon", "d_GridLayoutGroup Icon", "d_HorizontalLayoutGroup Icon",
            "d_Prefab Icon", "d_PrefabModel Icon", "d_PrefabVariant Icon", "d_VerticalLayoutGroup Icon",
            "DefaultSlate Icon", "DirectionalLight Gizmo", "DirectionalLight Icon", "DiscLight Gizmo", "DiscLight Icon",
            "dll Script Icon", "EchoFilter Icon", "Favorite Icon", "Folder Icon", "FolderEmpty Icon",
            "FolderFavorite Icon", "GameManager Icon", "GridBrush Icon", "HighPassFilter Icon",
            "HorizontalLayoutGroup Icon", "LensFlare Gizmo", "LightingDataAssetParent Icon", "LightProbeGroup Gizmo",
            "LightProbeProxyVolume Gizmo", "LowPassFilter Icon", "Main Light Gizmo", "MetaFile Icon",
            "Microphone Icon", "MuscleClip Icon", "ParticleSystem Gizmo", "PointLight Gizmo", "Prefab Icon",
            "PrefabModel Icon", "PrefabOverlayAdded Icon", "PrefabOverlayModified Icon", "PrefabOverlayRemoved Icon",
            "PrefabVariant Icon", "Projector Gizmo", "RaycastCollider Icon", "ReflectionProbe Gizmo",
            "ReverbFilter Icon", "SceneSet Icon", "Search Icon", "SoftlockProjectBrowser Icon", "SpeedTreeModel Icon",
            "SpotLight Gizmo", "Spotlight Icon", "SpriteCollider Icon", "sv_icon_dot0_pix16_gizmo",
            "sv_icon_dot10_pix16_gizmo", "sv_icon_dot11_pix16_gizmo", "sv_icon_dot12_pix16_gizmo",
            "sv_icon_dot13_pix16_gizmo", "sv_icon_dot14_pix16_gizmo", "sv_icon_dot15_pix16_gizmo",
            "sv_icon_dot1_pix16_gizmo", "sv_icon_dot2_pix16_gizmo", "sv_icon_dot3_pix16_gizmo",
            "sv_icon_dot4_pix16_gizmo", "sv_icon_dot5_pix16_gizmo", "sv_icon_dot6_pix16_gizmo",
            "sv_icon_dot7_pix16_gizmo", "sv_icon_dot8_pix16_gizmo", "sv_icon_dot9_pix16_gizmo",
            "AnimatorController Icon", "AnimatorState Icon", "AnimatorStateMachine Icon",
            "AnimatorStateTransition Icon", "BlendTree Icon", "AnimationWindowEvent Icon", "AudioMixerController Icon",
            "DefaultAsset Icon", "EditorSettings Icon", "AnyStateNode Icon", "HumanTemplate Icon",
            "LightingDataAsset Icon", "LightmapParameters Icon", "Preset Icon", "SceneAsset Icon",
            "SubstanceArchive Icon", "AssemblyDefinitionAsset Icon", "NavMeshAgent Icon", "NavMeshData Icon",
            "NavMeshObstacle Icon", "OffMeshLink Icon", "AnalyticsTracker Icon", "Animation Icon",
            "AnimationClip Icon", "AimConstraint Icon", "d_AimConstraint Icon", "d_LookAtConstraint Icon",
            "d_ParentConstraint Icon", "d_PositionConstraint Icon", "d_RotationConstraint Icon",
            "d_ScaleConstraint Icon", "LookAtConstraint Icon", "ParentConstraint Icon", "PositionConstraint Icon",
            "RotationConstraint Icon", "ScaleConstraint Icon", "Animator Icon", "AnimatorOverrideController Icon",
            "AreaEffector2D Icon", "AudioMixerGroup Icon", "AudioMixerSnapshot Icon", "AudioSpatializerMicrosoft Icon",
            "AudioChorusFilter Icon", "AudioClip Icon", "AudioDistortionFilter Icon", "AudioEchoFilter Icon",
            "AudioHighPassFilter Icon", "AudioListener Icon", "AudioLowPassFilter Icon", "AudioReverbFilter Icon",
            "AudioReverbZone Icon", "AudioSource Icon", "Avatar Icon", "AvatarMask Icon", "BillboardAsset Icon",
            "BillboardRenderer Icon", "BoxCollider Icon", "BoxCollider2D Icon", "BuoyancyEffector2D Icon",
            "Camera Icon",
            "Canvas Icon", "CanvasGroup Icon", "CanvasRenderer Icon", "CapsuleCollider Icon", "CapsuleCollider2D Icon",
            "CharacterController Icon", "CharacterJoint Icon", "CircleCollider2D Icon", "Cloth Icon",
            "CompositeCollider2D Icon", "ComputeShader Icon", "ConfigurableJoint Icon", "ConstantForce Icon",
            "ConstantForce2D Icon", "Cubemap Icon", "d_Canvas Icon", "d_CanvasGroup Icon", "d_CanvasRenderer Icon",
            "d_GameObject Icon", "d_LightProbeProxyVolume Icon", "d_ParticleSystem Icon",
            "d_ParticleSystemForceField Icon",
            "d_RectTransform Icon", "d_StreamingController Icon", "DistanceJoint2D Icon", "EdgeCollider2D Icon",
            "d_EventSystem Icon", "d_EventTrigger Icon", "d_Physics2DRaycaster Icon", "d_PhysicsRaycaster Icon",
            "d_StandaloneInputModule Icon", "d_TouchInputModule Icon", "EventSystem Icon", "EventTrigger Icon",
            "HoloLensInputModule Icon", "Physics2DRaycaster Icon", "PhysicsRaycaster Icon",
            "StandaloneInputModule Icon",
            "TouchInputModule Icon", "SpriteShapeRenderer Icon", "VisualTreeAsset Icon", "d_VisualEffect Icon",
            "d_VisualEffectAsset Icon", "VisualEffect Icon", "VisualEffectAsset Icon", "FixedJoint Icon",
            "FixedJoint2D Icon", "Flare Icon", "FlareLayer Icon", "Font Icon", "FrictionJoint2D Icon",
            "GameObject Icon", "Grid Icon", "GUILayer Icon", "GUISkin Icon", "GUIText Icon", "GUITexture Icon",
            "Halo Icon", "HingeJoint Icon", "HingeJoint2D Icon", "LensFlare Icon", "Light Icon", "LightProbeGroup Icon",
            "LightProbeProxyVolume Icon", "LightProbes Icon", "LineRenderer Icon", "LODGroup Icon", "Material Icon",
            "Mesh Icon", "MeshCollider Icon", "MeshFilter Icon", "MeshRenderer Icon", "Motion Icon",
            "MovieTexture Icon",
            "NetworkAnimator Icon", "NetworkDiscovery Icon", "NetworkIdentity Icon", "NetworkLobbyManager Icon",
            "NetworkLobbyPlayer Icon", "NetworkManager Icon", "NetworkManagerHUD Icon", "NetworkMigrationManager Icon",
            "NetworkProximityChecker Icon", "NetworkStartPosition Icon", "NetworkTransform Icon",
            "NetworkTransformChild Icon", "NetworkTransformVisualizer Icon", "NetworkView Icon", "OcclusionArea Icon",
            "OcclusionPortal Icon", "ParticleSystem Icon", "ParticleSystemForceField Icon", "PhysicMaterial Icon",
            "PhysicsMaterial2D Icon", "PlatformEffector2D Icon", "d_PlayableDirector Icon", "PlayableDirector Icon",
            "PointEffector2D Icon", "PolygonCollider2D Icon", "ProceduralMaterial Icon", "Projector Icon",
            "RectTransform Icon", "ReflectionProbe Icon", "RelativeJoint2D Icon", "d_SortingGroup Icon",
            "SortingGroup Icon", "RenderTexture Icon", "Rigidbody Icon", "Rigidbody2D Icon", "ScriptableObject Icon",
            "Shader Icon", "ShaderVariantCollection Icon", "SkinnedMeshRenderer Icon", "Skybox Icon",
            "SliderJoint2D Icon",
            "TrackedPoseDriver Icon", "SphereCollider Icon", "SpringJoint Icon", "SpringJoint2D Icon", "Sprite Icon",
            "SpriteMask Icon", "SpriteRenderer Icon", "StreamingController Icon", "StyleSheet Icon",
            "SurfaceEffector2D Icon",
            "TargetJoint2D Icon", "Terrain Icon", "TerrainCollider Icon", "TerrainData Icon", "TextAsset Icon",
            "TextMesh Icon", "Texture Icon", "Texture2D Icon", "Tile Icon", "Tilemap Icon", "TilemapCollider2D Icon",
            "TilemapRenderer Icon", "d_TimelineAsset Icon", "TimelineAsset Icon", "TrailRenderer Icon",
            "Transform Icon",
            "SpriteAtlas Icon", "AspectRatioFitter Icon", "Button Icon", "CanvasScaler Icon", "ContentSizeFitter Icon",
            "d_AspectRatioFitter Icon", "d_CanvasScaler Icon", "d_ContentSizeFitter Icon", "d_FreeformLayoutGroup Icon",
            "d_GraphicRaycaster Icon", "d_GridLayoutGroup Icon", "d_HorizontalLayoutGroup Icon", "d_LayoutElement Icon",
            "d_PhysicalResolution Icon", "d_ScrollViewArea Icon", "d_SelectionList Icon", "d_SelectionListItem Icon",
            "d_SelectionListTemplate Icon", "d_VerticalLayoutGroup Icon", "Dropdown Icon", "FreeformLayoutGroup Icon",
            "GraphicRaycaster Icon", "GridLayoutGroup Icon", "HorizontalLayoutGroup Icon", "Image Icon",
            "InputField Icon",
            "LayoutElement Icon", "Mask Icon", "Outline Icon", "PositionAsUV1 Icon", "RawImage Icon", "RectMask2D Icon",
            "Scrollbar Icon", "ScrollRect Icon", "Selectable Icon", "Shadow Icon", "Slider Icon", "Text Icon",
            "Toggle Icon",
            "ToggleGroup Icon", "VerticalLayoutGroup Icon", "VideoClip Icon", "VideoPlayer Icon", "VisualEffect Icon",
            "VisualEffectAsset Icon", "WheelCollider Icon", "WheelJoint2D Icon", "WindZone Icon",
            "SpatialMappingCollider Icon", "SpatialMappingRenderer Icon", "WorldAnchor Icon", "UssScript Icon",
            "UxmlScript Icon", "VerticalLayoutGroup Icon", "VideoEffect Icon", "VisualEffect Gizmo",
            "VisualEffectAsset Icon", "AnchorBehaviour Icon", "AnchorInputListenerBehaviour Icon",
            "AnchorStageBehaviour Icon", "CloudRecoBehaviour Icon", "ContentPlacementBehaviour Icon",
            "ContentPositioningBehaviour Icon", "CylinderTargetBehaviour Icon", "d_AnchorBehaviour Icon",
            "d_AnchorInputListenerBehaviour Icon", "d_AnchorStageBehaviour Icon", "d_CloudRecoBehaviour Icon",
            "d_ContentPlacementBehaviour Icon", "d_ContentPositioningBehaviour Icon", "d_CylinderTargetBehaviour Icon",
            "d_ImageTargetBehaviour Icon", "d_MidAirPositionerBehaviour Icon", "d_ModelTargetBehaviour Icon",
            "d_MultiTargetBehaviour Icon", "d_ObjectTargetBehaviour Icon", "d_PlaneFinderBehaviour Icon",
            "d_UserDefinedTargetBuildingBehaviour Icon", "d_VirtualButtonBehaviour Icon", "d_VuforiaBehaviour Icon",
            "d_VuMarkBehaviour Icon", "d_WireframeBehaviour Icon", "ImageTargetBehaviour Icon",
            "MidAirPositionerBehaviour Icon", "ModelTargetBehaviour Icon", "MultiTargetBehaviour Icon",
            "ObjectTargetBehaviour Icon", "PlaneFinderBehaviour Icon", "UserDefinedTargetBuildingBehaviour Icon",
            "VirtualButtonBehaviour Icon", "VuforiaBehaviour Icon", "VuMarkBehaviour Icon", "WireframeBehaviour Icon",
            "WindZone Gizmo", "Profiler.Audio", "Profiler.CPU", "Profiler.FirstFrame", "Profiler.GlobalIllumination",
            "Profiler.GPU", "Profiler.Instrumentation", "Profiler.LastFrame", "Profiler.Memory",
            "Profiler.NetworkMessages",
            "Profiler.NetworkOperations", "Profiler.NextFrame", "Profiler.Physics", "Profiler.Physics2D",
            "Profiler.PrevFrame", "Profiler.Record", "Profiler.Rendering", "Profiler.UI", "Profiler.UIDetails",
            "Profiler.Video", "ProfilerColumn.WarningCount", "Project", "RectTool On", "RectTool",
            "RectTransformBlueprint",
            "RectTransformRaw", "redGroove", "Refresh", "renderdoc", "rightBracket", "RotateTool On", "RotateTool",
            "SaveActive", "SaveFromPlay", "SavePassive", "ScaleTool On", "ScaleTool", "SceneLoadIn", "SceneLoadOut",
            "SceneSave", "SceneSaveGrey", "SceneViewAlpha", "SceneViewAudio", "SceneViewFx", "SceneViewLighting",
            "SceneViewOrtho", "SceneViewRGB", "ScrollShadow", "Settings", "SettingsIcon",
            "SocialNetworks.FacebookShare",
            "SocialNetworks.LinkedInShare", "SocialNetworks.Tweet", "SocialNetworks.UDNLogo", "SocialNetworks.UDNOpen",
            "SoftlockInline", "SpeedScale", "StateMachineEditor.ArrowTip", "StateMachineEditor.ArrowTipSelected",
            "StateMachineEditor.Background", "StateMachineEditor.State", "StateMachineEditor.StateHover",
            "StateMachineEditor.StateSelected", "StateMachineEditor.StateSub", "StateMachineEditor.StateSubHover",
            "StateMachineEditor.StateSubSelected", "StateMachineEditor.UpButton", "StateMachineEditor.UpButtonHover",
            "StepButton On", "StepButton", "StepLeftButton-On", "StepLeftButton", "sticky_arrow", "sticky_p4",
            "sticky_skin",
            "sv_icon_dot0_sml", "sv_icon_dot10_sml", "sv_icon_dot11_sml", "sv_icon_dot12_sml", "sv_icon_dot13_sml",
            "sv_icon_dot14_sml", "sv_icon_dot15_sml", "sv_icon_dot1_sml", "sv_icon_dot2_sml", "sv_icon_dot3_sml",
            "sv_icon_dot4_sml", "sv_icon_dot5_sml", "sv_icon_dot6_sml", "sv_icon_dot7_sml", "sv_icon_dot8_sml",
            "sv_icon_dot9_sml", "sv_icon_name0", "sv_icon_name1", "sv_icon_name2", "sv_icon_name3", "sv_icon_name4",
            "sv_icon_name5", "sv_icon_name6", "sv_icon_name7", "sv_icon_none", "sv_label_0", "sv_label_1", "sv_label_2",
            "sv_label_3", "sv_label_4", "sv_label_5", "sv_label_6", "sv_label_7", "SVN_AddedLocal", "SVN_Conflicted",
            "SVN_DeletedLocal", "SVN_Local", "SVN_LockedLocal", "SVN_OutOfSync", "tab_next", "tab_next@2x", "tab_prev",
            "tab_prev@2x", "TerrainInspector.TerrainToolLower On", "TerrainInspector.TerrainToolLower",
            "TerrainInspector.TerrainToolLowerAlt", "TerrainInspector.TerrainToolPlants On",
            "TerrainInspector.TerrainToolPlants", "TerrainInspector.TerrainToolPlantsAlt On",
            "TerrainInspector.TerrainToolPlantsAlt", "TerrainInspector.TerrainToolRaise On",
            "TerrainInspector.TerrainToolRaise", "TerrainInspector.TerrainToolSculpt On",
            "TerrainInspector.TerrainToolSculpt", "TerrainInspector.TerrainToolSetheight On",
            "TerrainInspector.TerrainToolSetheight", "TerrainInspector.TerrainToolSetheightAlt On",
            "TerrainInspector.TerrainToolSetheightAlt", "TerrainInspector.TerrainToolSettings On",
            "TerrainInspector.TerrainToolSettings", "TerrainInspector.TerrainToolSmoothHeight On",
            "TerrainInspector.TerrainToolSmoothHeight", "TerrainInspector.TerrainToolSplat On",
            "TerrainInspector.TerrainToolSplat", "TerrainInspector.TerrainToolSplatAlt On",
            "TerrainInspector.TerrainToolSplatAlt", "TerrainInspector.TerrainToolTrees On",
            "TerrainInspector.TerrainToolTrees", "TerrainInspector.TerrainToolTreesAlt On",
            "TerrainInspector.TerrainToolTreesAlt", "TestFailed", "TestIgnored", "TestInconclusive", "TestNormal",
            "TestPassed", "TestStopwatch", "TimelineClipBG", "TimelineClipFG", "TimelineDigIn",
            "TimelineEditModeMixOFF",
            "TimelineEditModeMixON", "TimelineEditModeReplaceOFF", "TimelineEditModeReplaceON",
            "TimelineEditModeRippleOFF",
            "TimelineEditModeRippleON", "TimelineSelector", "Toolbar Minus", "Toolbar Plus More", "Toolbar Plus",
            "ToolHandleCenter", "ToolHandleGlobal", "ToolHandleLocal", "ToolHandlePivot", "tranp", "TransformTool On",
            "TransformTool", "tree_icon", "tree_icon_branch", "tree_icon_branch_frond", "tree_icon_frond",
            "tree_icon_leaf",
            "TreeEditor.AddBranches", "TreeEditor.AddLeaves", "TreeEditor.Branch On", "TreeEditor.Branch",
            "TreeEditor.BranchFreeHand On", "TreeEditor.BranchFreeHand", "TreeEditor.BranchRotate On",
            "TreeEditor.BranchRotate", "TreeEditor.BranchScale On", "TreeEditor.BranchScale",
            "TreeEditor.BranchTranslate On", "TreeEditor.BranchTranslate", "TreeEditor.Distribution On",
            "TreeEditor.Distribution", "TreeEditor.Duplicate", "TreeEditor.Geometry On", "TreeEditor.Geometry",
            "TreeEditor.Leaf On", "TreeEditor.Leaf", "TreeEditor.LeafFreeHand On", "TreeEditor.LeafFreeHand",
            "TreeEditor.LeafRotate On", "TreeEditor.LeafRotate", "TreeEditor.LeafScale On", "TreeEditor.LeafScale",
            "TreeEditor.LeafTranslate On", "TreeEditor.LeafTranslate", "TreeEditor.Material On", "TreeEditor.Material",
            "TreeEditor.Refresh", "TreeEditor.Trash", "TreeEditor.Wind On", "TreeEditor.Wind",
            "UnityEditor.AnimationWindow",
            "UnityEditor.ConsoleWindow", "UnityEditor.DebugInspectorWindow", "UnityEditor.FindDependencies",
            "UnityEditor.GameView", "UnityEditor.Graphs.AnimatorControllerTool", "UnityEditor.HierarchyWindow",
            "UnityEditor.InspectorWindow", "UnityEditor.LookDevView", "UnityEditor.ProfilerWindow",
            "UnityEditor.SceneHierarchyWindow", "UnityEditor.SceneView", "UnityEditor.Timeline.TimelineWindow",
            "UnityEditor.VersionControl", "UnityLogo", "UnityLogoLarge", "UpArrow", "vcs_add", "vcs_branch",
            "vcs_change",
            "vcs_check", "vcs_delete", "vcs_document", "vcs_edit", "vcs_incoming", "vcs_integrate", "vcs_local",
            "vcs_lock",
            "vcs_refresh", "vcs_sync", "vcs_unresolved", "vcs_update", "VerticalSplit", "ViewToolMove On",
            "ViewToolMove",
            "ViewToolOrbit On", "ViewToolOrbit", "ViewToolZoom On", "ViewToolZoom", "VisibilityOff", "VisibilityOn",
            "VisualEffect Gizmo", "VUMeterTextureHorizontal", "VUMeterTextureVertical", "WaitSpin00", "WaitSpin01",
            "WaitSpin02", "WaitSpin03", "WaitSpin04", "WaitSpin05", "WaitSpin06", "WaitSpin07", "WaitSpin08",
            "WaitSpin09",
            "WaitSpin10", "WaitSpin11", "WelcomeScreen.AssetStoreLogo", "winbtn_graph", "winbtn_graph_close_h",
            "winbtn_graph_max_h", "winbtn_graph_min_h", "winbtn_mac_close", "winbtn_mac_close_a", "winbtn_mac_close_h",
            "winbtn_mac_inact", "winbtn_mac_max", "winbtn_mac_max_a", "winbtn_mac_max_h", "winbtn_mac_min",
            "winbtn_mac_min_a", "winbtn_mac_min_h", "winbtn_win_close", "winbtn_win_close_a", "winbtn_win_close_h",
            "winbtn_win_max", "winbtn_win_max_a", "winbtn_win_max_h", "winbtn_win_min", "winbtn_win_min_a",
            "winbtn_win_min_h", "winbtn_win_rest", "winbtn_win_rest_a", "winbtn_win_rest_h",
            "AvatarInspector/RightFingersIk", "AvatarInspector/LeftFingersIk", "AvatarInspector/RightFeetIk",
            "AvatarInspector/LeftFeetIk", "AvatarInspector/RightFingers", "AvatarInspector/LeftFingers",
            "AvatarInspector/RightArm", "AvatarInspector/LeftArm", "AvatarInspector/RightLeg",
            "AvatarInspector/LeftLeg",
            "AvatarInspector/Head", "AvatarInspector/Torso", "AvatarInspector/MaskEditor_Root",
            "AvatarInspector/BodyPartPicker", "AvatarInspector/BodySIlhouette", "boo Script Icon", "js Script Icon",
            "EyeDropper.Large", "AboutWindow.MainHeader", "AgeiaLogo", "MonoLogo", "PlayButtonProfile Anim",
            "StepButton Anim", "PauseButton Anim", "PlayButton Anim", "MoveTool On", "Icon Dropdown",
            "AvatarInspector/DotSelection", "AvatarInspector/DotFrameDotted", "AvatarInspector/DotFrame",
            "AvatarInspector/DotFill", "AvatarInspector/RightHandZoom", "AvatarInspector/LeftHandZoom",
            "AvatarInspector/HeadZoom", "AvatarInspector/RightLeg", "AvatarInspector/LeftLeg",
            "AvatarInspector/RightFingers", "AvatarInspector/RightArm", "AvatarInspector/LeftFingers",
            "AvatarInspector/LeftArm", "AvatarInspector/Head", "AvatarInspector/Torso",
            "AvatarInspector/RightHandZoomSilhouette", "AvatarInspector/LeftHandZoomSilhouette",
            "AvatarInspector/HeadZoomSilhouette", "AvatarInspector/BodySilhouette", "lightMeter/redLight",
            "lightMeter/orangeLight", "lightMeter/lightRim", "lightMeter/greenLight", "SceneviewAudio",
            "SceneviewLighting", "TerrainInspector.TerrainToolSetHeight", "AS Badge New", "AS Badge Move",
            "AS Badge Delete", "WelcomeScreen.UnityAnswersLogo", "WelcomeScreen.UnityForumLogo",
            "WelcomeScreen.UnityBasicsLogo", "WelcomeScreen.VideoTutLogo", "WelcomeScreen.MainHeader", "Icon Dropdown",
            "PrefabNormal Icon", "PrefabNormal Icon", "BuildSettings.BlackBerry.Small", "BuildSettings.Tizen.Small",
            "BuildSettings.XBox360.Small", "BuildSettings.PS3.Small", "BuildSettings.SamsungTV.Small",
            "BuildSettings.BlackBerry", "BuildSettings.Tizen", "BuildSettings.XBox360", "BuildSettings.PS3",
            "BuildSettings.SamsungTV"
        };

        #endregion
    }
}



<|start_filename|>Runtime/UI/Wrap/TmpWrapper.cs<|end_filename|>
using System;
using System.Globalization;
using Framework.UI.Core;
using Framework.UI.Wrap.Base;
using TMPro;
using UnityEngine.UI;

namespace Framework.UI.Wrap
{
    public class TmpWrapper : BaseWrapper<TextMeshProUGUI>, IFieldChangeCb<string>, IFieldChangeCb<int>, IFieldChangeCb<float>,
        IFieldChangeCb<double>, IFieldChangeCb<long>
    {
        Action<string> IFieldChangeCb<string>.GetFieldChangeCb()
        {
            return (value) => Component.text = value;
        }

        public Action<int> GetFieldChangeCb()
        {
            return value => Component.text = value.ToString();
        }

        Action<float> IFieldChangeCb<float>.GetFieldChangeCb()
        {
            return value => Component.text = value.ToString(CultureInfo.InvariantCulture);
        }

        Action<double> IFieldChangeCb<double>.GetFieldChangeCb()
        {
            return value => Component.text = value.ToString(CultureInfo.InvariantCulture);
        }

        Action<long> IFieldChangeCb<long>.GetFieldChangeCb()
        {
            return value => Component.text = value.ToString(CultureInfo.InvariantCulture);
        }

        public TmpWrapper(TextMeshProUGUI component, View view) : base(component, view)
        {
        }
    }
}

<|start_filename|>Runtime/Domain/Context/Context.cs<|end_filename|>
/*
 * MIT License
 *
 * Copyright (c) 2018 <NAME>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of 
 * this software and associated documentation files (the "Software"), to deal in 
 * the Software without restriction, including without limitation the rights to 
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
 * of the Software, and to permit persons to whom the Software is furnished to do so, 
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all 
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
 * SOFTWARE.
 */

using System.Collections.Generic;
using Tool;

namespace Framework.Contexts
{
    public class Context
    {
        private static ApplicationContext context = new ApplicationContext();
        private static Dictionary<string, Context> contexts = new Dictionary<string, Context>();
        public static ApplicationContext GetApplicationContext()
        {
            return Context.context;
        }

        public static void SetApplicationContext(ApplicationContext context)
        {
            Context.context = context;
        }
        
        public static Context GetContext(string key)
        {
            Context context = null;
            contexts.TryGetValue(key, out context);
            return context;
        }

        public static T GetContext<T>(string key) where T : Context
        {
            return (T)GetContext(key);
        }

        public static T GetContext<T>() where T : Context
        {
            return (T) GetContext(typeof(T).Name);
        }

        public static void AddContext<T>(T context) where T : Context
        {
            AddContext(context.GetCLRType().Name, context);
        }

        public static void AddContext(string key, Context context)
        {
            contexts.Add(key, context);
        }

        public static void RemoveContext<T>()
        {
            RemoveContext(typeof(T).Name);
        }

        public static void RemoveContext(string key)
        {
            if (contexts.ContainsKey(key))
                contexts.Remove(key);
        }
        
        private bool _innerContainer;
        private Context _contextBase;
        private Dictionary<string, object> _attributes;

        public Context() : this(null)
        {
        }

        public Context(Context contextBase)
        {
            _attributes = new Dictionary<string, object>();
            _contextBase = contextBase;
        }
        
        public virtual bool Contains(string name, bool cascade = true)
        {
            if (this._attributes.ContainsKey(name))
                return true;

            if (cascade && this._contextBase != null)
                return this._contextBase.Contains(name, cascade);

            return false;
        }
        
        public virtual bool Contains<T>( bool cascade = true)
        {
            return Contains(typeof(T).Name, cascade);
        }

        public virtual object Get(string name, bool cascade = true)
        {
            return this.Get<object>(name, cascade);
        }

        public virtual T Get<T>(bool cascade = true)
        {
            return Get<T>(typeof(T).Name, cascade);
        }
        
        public virtual T Get<T>(string name, bool cascade = true)
        {
            object v;
            if (this._attributes.TryGetValue(name, out v))
                return (T)v;

            if (cascade && this._contextBase != null)
                return this._contextBase.Get<T>(name, cascade);

            return default(T);
        }

        public virtual void Set(string name, object value)
        {
            this._attributes[name] = value;
        }

        public virtual void Set<T>(T value)
        {
            Set(typeof(T).Name, value);
        }

        public virtual object Remove(string name)
        {
            return this.Remove<object>(name);
        }

        public virtual T Remove<T>()
        {
            return Remove<T>(typeof(T).Name);
        }

        public virtual T Remove<T>(string name)
        {
            if (!this._attributes.ContainsKey(name))
                return default(T);

            object v = this._attributes[name];
            this._attributes.Remove(name);
            return (T)v;
        }
    }
}

<|start_filename|>Runtime/Domain/IDomain.cs<|end_filename|>
namespace Framework
{
    public interface IDomain
    {
        int Name { get; }
        bool IsLoad { get;  }
        void BeginEnter(object data = null);
        void BeginExit();
    }
}

<|start_filename|>Editor/BuildConfig/FrameworkEditorConfig.cs<|end_filename|>
using System;
using Sirenix.OdinInspector;
using UnityEngine;

namespace Framework.Editor
{
    [ShowOdinSerializedPropertiesInInspector]
    public class FrameworkEditorConfig : ConfigBase 
    {
        [FoldoutGroup("打包设置",expanded: true)]
        [BoxGroup("打包设置/Android设置")]
        [HideLabel]
        [InlinePropertyAttribute]
        public AndroidConfig Android = new AndroidConfig();

        [BoxGroup("打包设置/Ios设置")]
        [HideLabel]
        [InlinePropertyAttribute]
        public IosConfig IosConfig =new IosConfig();

        [FolderPath]
        [LabelText("打包输出路径")]
        public string OutputPath;
        
        [FoldoutGroup("UI设置", expanded: true)]
        [HideLabel]
        [InlinePropertyAttribute]
        public UIConfig UIConfig = new UIConfig();
    }
    
    [Serializable]
    public class AndroidConfig
    {
        [LabelText("Keystore路径")]
        [FilePath(Extensions = "keystore", AbsolutePath = false)]
        public string KeystoreName = "../key.keystore";
        [LabelText("Keystore密码")]
        public string KeystorePwd = "";
        [LabelText("keyalias")]
        public string KeyAliasName;
        [LabelText("keyalias密码")]
        public string KeyAliasPwd;
    }

    [Serializable]
    public class IosConfig
    {
        [LabelText("证书")]
        public string Liscene;
        [LabelText("密钥")]
        public string Keystore;
    }
    
    [Serializable]
    public class UIConfig
    {
        [FolderPath(AbsolutePath = false)]
        [LabelText("自动生成UI代码的路径")]
        public string GenUIScriptsPath = "Assets/_Scripts/UI";
    }
}

<|start_filename|>Runtime/Common/Singleton/MonoSingleton.cs<|end_filename|>
using UnityEngine;

namespace Framework
{
	public class MonoSingleton<T>  : MonoBehaviour where T : MonoSingleton<T>
	{
		private static T instance = null;
		
		private static readonly object locker = new object ();

		public static T Ins
		{
			get
			{
				lock ( locker )
				{
					if ( null == instance )
					{
						instance = MonoSingletonCreator.CreateMonoSingleton<T>();
					}
				}

				return instance;
			}
		}
	}
}


<|start_filename|>Runtime/Tool/Net/ProgressInfo.cs<|end_filename|>
﻿/*
 * MIT License
 *
 * Copyright (c) 2018 <NAME>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of 
 * this software and associated documentation files (the "Software"), to deal in 
 * the Software without restriction, including without limitation the rights to 
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
 * of the Software, and to permit persons to whom the Software is furnished to do so, 
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all 
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
 * SOFTWARE.
 */

using System;
using System.Globalization;
using Framework.Asynchronous;

namespace Framework.Net
{
    public enum UNIT
    {
        BYTE,
        KB,
        MB,
        GB
    }

    public class ProgressInfo : IMulProgress
    {
        private long _totalSize = 0;
        private long _completedSize = 0;

        private float _speed = 0f;
        private long _lastTime = -1;
        private long _lastValue = -1;
        private long _lastTime2 = -1;
        private long _lastValue2 = -1;

        public ProgressInfo() : this(0, 0)
        {
        }

        public ProgressInfo(long totalSize, long completedSize)
        {
            this._totalSize = totalSize;
            this._completedSize = completedSize;

            _lastTime = DateTime.UtcNow.Ticks / 10000;
            _lastValue = this._completedSize;

            _lastTime2 = _lastTime;
            _lastValue2 = _lastValue;
        }

        public long TotalSize
        {
            get => this._totalSize;
            set => this._totalSize = value;
        }
        public long CompletedSize
        {
            get => this._completedSize;
            set
            {
                this._completedSize = value;
                this.OnUpdate();
            }
        }

        public int TotalCount { get; set; } = 0;

        public int CompletedCount { get; set; } = 0;

        private void OnUpdate()
        {
            long now = DateTime.UtcNow.Ticks / 10000;

            if ((now - _lastTime) >= 1000)
            {
                _lastTime2 = _lastTime;
                _lastValue2 = _lastValue;

                this._lastTime = now;
                this._lastValue = this._completedSize;
            }

            float dt = (now - _lastTime2) / 1000f;
            _speed = (this._completedSize - this._lastValue2) / dt;
        }

        public virtual float Progress
        {
            get
            {
                if (this._totalSize <= 0)
                    return 0f;

                return this._completedSize / (float)this._totalSize;
            }
        }

        public virtual float GetTotalSize(UNIT unit = UNIT.BYTE)
        {
            switch (unit)
            {
                case UNIT.KB:
                    return this._totalSize / 1024f;
                case UNIT.MB:
                    return this._totalSize / 1048576f;
                case UNIT.GB:
                    return this._totalSize / 1073741824f;
                default:
                    return (float)this._totalSize;
            }
        }

        public virtual float GetCompletedSize(UNIT unit = UNIT.BYTE)
        {
            switch (unit)
            {
                case UNIT.KB:
                    return this._completedSize / 1024f;
                case UNIT.MB:
                    return this._completedSize / 1048576f;
                case UNIT.GB:
                    return this._completedSize / 1073741824f;
                default:
                    return (float)this._completedSize;
            }
        }

        public virtual float GetSpeed(UNIT unit = UNIT.BYTE)
        {
            switch (unit)
            {
                case UNIT.KB:
                    return _speed / 1024f;
                case UNIT.MB:
                    return _speed / 1048576f;
                case UNIT.GB:
                    return _speed / 1073741824f;
                default:
                    return _speed;
            }
        }

        public override string ToString()
        {
            return $"{GetCompletedSize()} / {GetTotalSize()} ";
        }

        public float Current => _completedSize;
        public float Total => _totalSize;
    }
}

<|start_filename|>Runtime/Common/ScriptCollection/EventTriggerListener.cs<|end_filename|>
using System;
using UnityEngine;
using UnityEngine.EventSystems;

/// <summary>
/// UI点击事件 包含onClick onDown onEnter onExit onUp onSelect onUpdateSelect
/// </summary>
public class EventTriggerListener : EventTrigger
{
    public delegate void VoidDelegate2(PointerEventData eventData);
    public event Action onClick;
    public event Action onDown;
    public event Action onDrag;
    public event Action<PointerEventData> onEndDrag;
    public event Action<PointerEventData> onScroll;
    public event Action onEnter;
    public event Action onExit;
    public event Action onUp;
    public event Action onSelect;
    public event Action onUpdateSelect;

    public static EventTriggerListener Get(GameObject go)
    {
        EventTriggerListener listener = go.GetComponent<EventTriggerListener>();
        if (listener == null) listener = go.AddComponent<EventTriggerListener>();
        return listener;
    }

    public override void OnDrag(PointerEventData eventData)
    {
        onDrag?.Invoke();
    }
    public override void OnPointerClick(PointerEventData eventData)
    {
        onClick?.Invoke();
    }
    public override void OnPointerDown(PointerEventData eventData)
    {
        onDown?.Invoke();
    }
    public override void OnPointerEnter(PointerEventData eventData)
    {
        onEnter?.Invoke();
    }
    public override void OnPointerExit(PointerEventData eventData)
    {
        onExit?.Invoke();
    }
    public override void OnPointerUp(PointerEventData eventData)
    {
        onUp?.Invoke();
    }
    public override void OnSelect(BaseEventData eventData)
    {
        onSelect?.Invoke();
    }
    public override void OnUpdateSelected(BaseEventData eventData)
    {
        onUpdateSelect?.Invoke();
    }

    public override void OnEndDrag(PointerEventData eventData)
    {
        onEndDrag?.Invoke(eventData);
    }

    public override void OnScroll(PointerEventData eventData)
    {
        onScroll?.Invoke(eventData);
    }

}



<|start_filename|>Runtime/UI/Core/UIMark.cs<|end_filename|>
﻿using System.Collections.Generic;
using System.Linq;
using Sirenix.OdinInspector;
using UnityEngine;
using UnityEngine.UI;

[ExecuteInEditMode]
public class UIMark : MonoBehaviour
{
#if UNITY_EDITOR
    public string FieldName;

    [ValueDropdown("Components")]
    public Object CurComponent;

    private List<Object> Components;

    public bool IgnoreSelf;

    public bool IgnoreChild;

    private void Awake()
    {
        RefreshComponent();
        if (!string.IsNullOrEmpty(FieldName)) return;
        FieldName = gameObject.name;
        foreach (var component in Components)
        {
            if (component == DefaultComponent)
            {
                CurComponent = component;
                break;
            }
        }
    }

    private void Update()
    {
        RefreshComponent();
    }

    private void RefreshComponent()
    {
        Components = gameObject.GetComponents<Component>().Select((component => (Object)component)).ToList();
        Components.Add(gameObject);
    }

    private Component DefaultComponent
    {
        get
        {
            if (GetComponent<ScrollRect>()) return GetComponent<ScrollRect>();
            if (GetComponent<InputField>()) return GetComponent<InputField>();

            // text mesh pro supported
            if (GetComponent("TMP.TextMeshProUGUI")) return GetComponent("TMP.TextMeshProUGUI");
            if (GetComponent("TMPro.TextMeshProUGUI")) return GetComponent("TMPro.TextMeshProUGUI");
            if (GetComponent("TMPro.TextMeshPro")) return GetComponent("TMPro.TextMeshPro");
            if (GetComponent("TMPro.TMP_InputField")) return GetComponent("TMPro.TMP_InputField");

            // ugui bind
            if (GetComponent<Dropdown>()) return GetComponent<Dropdown>();
            if (GetComponent<Button>()) return GetComponent<Button>();
            if (GetComponent<Text>()) return GetComponent<Text>();
            if (GetComponent<RawImage>()) return GetComponent<RawImage>();
            if (GetComponent<Toggle>()) return GetComponent<Toggle>();
            if (GetComponent<Slider>()) return GetComponent<Slider>();
            if (GetComponent<Scrollbar>()) return GetComponent<Scrollbar>();
            if (GetComponent<Image>()) return GetComponent<Image>();
            if (GetComponent<ToggleGroup>()) return GetComponent<ToggleGroup>();

            // other
            if (GetComponent<Rigidbody2D>()) return GetComponent<Rigidbody2D>();
            if (GetComponent<BoxCollider2D>()) return GetComponent<BoxCollider2D>();
            if (GetComponent<CircleCollider2D>()) return GetComponent<CircleCollider2D>();
            if (GetComponent<Collider2D>()) return GetComponent<Collider2D>();
            if (GetComponent<Animator>()) return GetComponent<Animator>();
            if (GetComponent<Canvas>()) return GetComponent<Canvas>();
            if (GetComponent<Camera>()) return GetComponent<Camera>();
            if (GetComponent<RectTransform>()) return GetComponent<RectTransform>();
            if (GetComponent<Transform>()) return GetComponent<Transform>();
            if (GetComponent<MeshRenderer>()) return GetComponent<MeshRenderer>();
            if (GetComponent<SpriteRenderer>()) return GetComponent<SpriteRenderer>();
            return null;
        }
    }
#endif
}


<|start_filename|>Plugins/IngameDebugConsole/Scripts/DebugLogTips.cs<|end_filename|>
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.UI;

namespace IngameDebugConsole
{
    public class DebugLogTips : MonoBehaviour
    {
        private static DebugLogTips ins;
        private CanvasGroup canvasGroup;
        [SerializeField]
        private Text text;
        private void Start()
        {
            ins = this;
            canvasGroup = GetComponent<CanvasGroup>();
        }

        public static void ShowTips(string text)
        {
            ins.canvasGroup.alpha = 1;
            ins.gameObject.SetActive(true);
            ins.text.text = text;
            ins.StartCoroutine(ins.Delay(2, () => ins.canvasGroup.alpha = 0));
        }
        
        IEnumerator Delay(float time, Action action)
        {
            yield return new WaitForSeconds(time);
            action();
        }
    }
}

<|start_filename|>Runtime/Assets/ComponentReference.cs<|end_filename|>
#if ADDRESSABLE
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
#if UNITY_EDITOR
using UnityEditor;
#endif

namespace Framework.Assets
{
    public class ComponentReference<TComponent> : AssetReference
    {
        public ComponentReference(string guid) : base(guid)
        {
        }

        public new AsyncOperationHandle<TComponent> InstantiateAsync(Vector3 position, Quaternion rotation,
            Transform parent = null)
        {
            return Addressables.ResourceManager.CreateChainOperation<TComponent, GameObject>(
                base.InstantiateAsync(position, Quaternion.identity, parent), GameObjectReady);
        }

        public new AsyncOperationHandle<TComponent> InstantiateAsync(Transform parent = null,
            bool instantiateInWorldSpace = false)
        {
            return Addressables.ResourceManager.CreateChainOperation<TComponent, GameObject>(
                base.InstantiateAsync(parent, instantiateInWorldSpace), GameObjectReady);
        }

        public AsyncOperationHandle<TComponent> LoadAssetAsync()
        {
            return Addressables.ResourceManager.CreateChainOperation<TComponent, GameObject>(
                base.LoadAssetAsync<GameObject>(), GameObjectReady);
        }

        AsyncOperationHandle<TComponent> GameObjectReady(AsyncOperationHandle<GameObject> arg)
        {
            var comp = arg.Result.GetComponent<TComponent>();
            return Addressables.ResourceManager.CreateCompletedOperation<TComponent>(comp, string.Empty);
        }

        public override bool ValidateAsset(Object obj)
        {
            var go = obj as GameObject;
            return go != null && go.GetComponent<TComponent>() != null;
        }

        public override bool ValidateAsset(string path)
        {
#if UNITY_EDITOR
            //this load can be expensive...
            var go = AssetDatabase.LoadAssetAtPath<GameObject>(path);
            return go != null && go.GetComponent<TComponent>() != null;
#else
            return false;
#endif
        }

        public void ReleaseInstance(AsyncOperationHandle<TComponent> op)
        {
            // Release the instance
            var component = op.Result as Component;
            if (component != null)
            {
                Addressables.ReleaseInstance(component.gameObject);
            }

            // Release the handle
            Addressables.Release(op);
        }
    }
}
#endif

<|start_filename|>Runtime/Tool/UIHelper.cs<|end_filename|>
﻿using System;
using Framework.Execution;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using IAsyncResult = Framework.Asynchronous.IAsyncResult;

namespace Framework.Helper
{
    public class UIHelper
    {
        public static void TextTyperEffect(Text textComponent, string content, long delta, Action onComplete)
        {
            if (null != textComponent && !string.IsNullOrEmpty(content))
            {
                textComponent.text = "";
                int length = 1;
                ITimerExecutor timerExecutor = new CoroutineTimerExecutor();
                IAsyncResult asyncResult = null;
                asyncResult = timerExecutor.FixedRateAtDuration(deltaTime =>
                {
                    var subContent = content.Substring(0, length);
                    textComponent.text = subContent;
                    length++;
                    if (length > content.Length)
                    {
                        onComplete?.Invoke();
                        asyncResult.Cancel();
                    }
                }, period: delta);
            }
        }

        /// <summary>
        /// 切割一张Texure大图上面的一部分，作为Sprite精灵返回
        /// </summary>
        /// <returns></returns>
        public static Sprite SliceTextureToSprite(Texture2D texture2D, float x, float y, float width, float height)
        {
            if (null != texture2D)
            {
                if (x + width > texture2D.width)
                {
                    width = texture2D.width - x;
                    Log.Warning("the width is larger then texture2D width!");
                }

                if (y + height > texture2D.height)
                {
                    height = texture2D.height - y;
                    Log.Warning("the height is larger then texture2D height!");
                }

                Sprite sprite = Sprite.Create(texture2D, new Rect(x, y, width, height), new Vector2(0.5f, 0.5f));
                return sprite;
            }

            Log.Warning("Texture2D 不能为空！");

            return null;
        }

        public static bool TouchInUI()
        {
            #if IPHONE || ANDROID
            			if (Input.touchCount > 0 && EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId)) return true;
            #else
                    if (EventSystem.current.IsPointerOverGameObject()) return true;
            #endif
            return false;
        }
    }
}

<|start_filename|>Runtime/Launch.cs<|end_filename|>
﻿// using System;
// using System.Collections.Generic;
// using System.Linq;
// using System.Reflection;
// using System.Threading.Tasks;
// using Framework;
// using Framework.Asynchronous;
// using Framework.UI.Core;
// using UnityEngine;
// using VEngine;
// using Logger = VEngine.Logger;
//
// public class Launch : MonoBehaviour
// {
//
// 	private bool useHotfix;
// 	private bool debug = false;
// 	public ManifestInfo[] ManifestInfos;
// 	
// 	private void Awake()
// 	{
// 		useHotfix = ConfigBase.Load<FrameworkRuntimeConfig>().ILRConfig.UseHotFix;
// 		CheckDownload();
// 	}
// 	
// 	private async void CheckDownload()
// 	{
// 		Logger.Loggable = false;
// 		Versions.addressableByName = path => true;
// 		await Versions.InitializeAsync(ManifestInfos);
// 		var uiRoot = GameObject.Find("UIRoot").transform;
// 		var checkWindow = new Window_CheckRes();
// 		checkWindow.SetVm(new Window_CheckResVM(InitGame));
// 		var checkTrans = new GameObject(nameof(Window_CheckRes)).transform;
// 		checkTrans.SetParent(uiRoot, false);
// 		checkWindow.SetGameObject(checkTrans.gameObject);
// 	}
//
// 	private async void InitGame()
// 	{
// 		var ilrTypes = await LoadHotFix();
// 		ParseTypes(ilrTypes.Distinct());
// 		if (debug) return;
// 		var logo = UIManager.Ins.Canvas.transform.Find("Logo");
// 		if (logo != null)
// 			Destroy(logo.gameObject);
// 	}
//
// 	private void Start()
// 	{
// 		GMCommand.Init();
// 	}
//
// 	private void ParseTypes(IEnumerable<Type> ilrTypes)
// 	{
// 		//编辑器环境下 寻找dll
// 		List<Type> allTypes = new List<Type>();
// 		allTypes.AddRange(GetType().Assembly.GetTypes());
// 		allTypes.AddRange(typeof(IManager).Assembly.GetTypes());
//
// 		var mgrs = new List<IManager>();
// 		List<Type> managerAttributeTypes = new List<Type>();
//
// 		//寻找所有的管理器
// 		allTypes = allTypes.Distinct().ToList();
// 		foreach (var t in allTypes)
// 		{
// 			if (t != null
// 			    && t.BaseType != null
// 			    && t.BaseType.FullName != null
// 			    && t.BaseType.FullName.Contains(".ManagerBase`3"))
// 			{
// 				var i = t.BaseType.GetProperty("Ins", BindingFlags.Public | BindingFlags.Static)
// 					?.GetValue(null, null) as IManager;
// 				mgrs.Add(i);
// 				continue;
// 			}
// 			//非热更dll需要查找adaptor
// 			if (ILRuntimeAdapterHelper.AddAdaptor(t))
// 			{
// 				continue;
// 			}
// 			if (t.GetCustomAttributes(typeof(ManagerAttribute),false).Length > 0)
// 			{
// 				managerAttributeTypes.Add(t);
// 				continue;
// 			}
// 			//找到热更注册的方法
// 			if (t.GetCustomAttribute(typeof(HotfixInitAttribute), false) != null)
// 			{
// 				hotfixInitMethod.Add(t.GetMethods().First(info => info.GetCustomAttribute(typeof(HotfixInitAttribute)) != null));
// 			}
// 			
// 		}
// 		
// 		//查找完adaptor才能注册各种适配
// 		if (useHotfix)
// 			InitializeILRuntime();
// 		
// 		HotfixEnterGame();
// 		if (debug) return;
// 		foreach (var t in ilrTypes)
// 		{
// 			if (t != null
// 			    && t.BaseType != null
// 			    && t.BaseType.FullName != null
// 			    && t.BaseType.FullName.Contains(".ManagerBase`3"))
// 			{
// 				var i = t.BaseType.GetProperty("Ins", BindingFlags.Public | BindingFlags.Static)
// 					?.GetValue(null, null) as IManager;
// 				mgrs.Add(i);
// 				continue;
// 			}
// 			if (t.GetCustomAttributes(false).Length > 0)
// 			{
// 				managerAttributeTypes.Add(t);
// 			}
// 		}
//
// 		//类型注册
// 		foreach (var t in managerAttributeTypes)
// 		{
// 			foreach (var iMgr in mgrs)
// 			{
// 				iMgr.CheckType(t);
// 			}
// 		}
//
// 		//管理器初始化
// 		foreach (var m in mgrs)
// 		{
// 			m.Init();
// 		}
//
// 		//所有管理器开始工作
// 		foreach (var m in mgrs)
// 		{
// 			m.Start();
// 		}
// 	}
//
// 	private async Task<List<Type>> LoadHotFix()
// 	{
// 		List<Type> result = new List<Type>();
// 		Log.Msg("use hotfix :", useHotfix);
// 		if (!useHotfix)
// 		{
// 			result.AddRange(GetComponent($"HotfixEntry").GetType().Assembly.DefinedTypes);
// 		}
// 		else
// 		{
// 			await ILRuntimeHelper.LoadILRuntime();
// 			result.AddRange(ILRuntimeHelper.GetHotfixTypes());
// 		}
// 		return result;
// 	}
// 	
// 	private void HotfixEnterGame()
// 	{
// 		if (useHotfix)
// 		{
// 			ILRuntimeHelper.Appdomain.Invoke("HotfixEntry", "RunGame", null, null);
// 		}
// 		else
// 		{
// 			GetComponent($"HotfixEntry").GetType().GetMethod("RunGame", BindingFlags.Static | BindingFlags.Public)
// 				.Invoke(null, null);
// 		}
// 	}
//
// 	private List<MethodInfo> hotfixInitMethod = new List<MethodInfo>();
// 	
// 	private void InitializeILRuntime()
// 	{
// 		var appdomain = ILRuntimeHelper.Appdomain;
// 		ILRuntimeHelper.InitializeILRuntime(appdomain);
// 		var para = new object[] {appdomain};
// 		foreach (var methodInfo in hotfixInitMethod)
// 		{
// 			methodInfo.Invoke(null, para);
// 		}
// 	}
//
// }

<|start_filename|>Runtime/Tool/GameLoop.cs<|end_filename|>
using System;

namespace Framework
{
    public class GameLoop : MonoSingleton<GameLoop>
    {
        public event Action OnUpdate;
        public event Action OnLateUpdate;
        public event Action OnFixedUpdate;
        public event Action OnApplicationQuitEvent;
        public event Action<bool> OnApplicationFocusEvent; 
        public event Action<bool> OnApplicationPauseEvent; 

        private void Update()
        {
            OnUpdate?.Invoke();
        }

        private void FixedUpdate()
        {
            OnFixedUpdate?.Invoke();
        }

        private void LateUpdate()
        {
            OnLateUpdate?.Invoke();
        }

        private void OnApplicationQuit()
		{
            OnApplicationQuitEvent?.Invoke();
		}

        private void OnApplicationFocus(bool hasFocus)
        {
            OnApplicationFocusEvent?.Invoke(hasFocus);
        }

        private void OnApplicationPause(bool pauseStatus)
        {
            OnApplicationPauseEvent?.Invoke(pauseStatus);
        }
    }
}

<|start_filename|>Runtime/Tool/FApplication.cs<|end_filename|>
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEngine;

namespace Framework
{
    /// <summary>
    /// 职责类似Unity的Application
    /// </summary>
    public static class FApplication
    {
        #region 路径相关
#if UNITY_EDITOR
        static  FApplication()
        {
            Init();
        }

        private static void Init()
        {
            ProjectRoot = Application.dataPath.Replace("/Assets", "");
            AssetsRoot = Application.dataPath;
            Library = ProjectRoot + "/Library";
        }
        /// <summary>
        /// 项目根目录
        /// Assets的同级目录
        /// </summary>
        public static string ProjectRoot { get; private set; }
        public static string AssetsRoot { get; private set; }
        /// <summary>
        /// Library
        /// </summary>
        public static string Library { get; private set; }
        
        public static string GetPlatformPath(UnityEditor.BuildTarget platform)
        {
            switch (platform)
            {
                case UnityEditor.BuildTarget.StandaloneOSX:
                    return "OSX";
                case UnityEditor.BuildTarget.StandaloneWindows:
                    return "Windows";
                case UnityEditor.BuildTarget.Android:
                    return "Android";
                case UnityEditor.BuildTarget.iOS:
                    return "iOS";
            }

            return "";
        }
#endif
        /// <summary>
        /// 平台资源的父路径
        /// </summary>
        public static string GetPlatformPath(RuntimePlatform platform)
        {
            switch (platform)
            {
                case RuntimePlatform.OSXEditor:
                case RuntimePlatform.OSXPlayer:
                    return "OSX";
                case RuntimePlatform.WindowsEditor:
                case RuntimePlatform.WindowsPlayer:
                    return "Windows";
                case RuntimePlatform.Android:
                    return "Android";
                case RuntimePlatform.IPhonePlayer:
                    return "iOS";
            }

            return "";
        }
        
       
        #endregion

        /// <summary>
        /// UnityWebRequest加载
        /// StreamingAssets 下， mac/win要加file:///  安卓不能加
        /// persistent下 都要加file:///
        ///
        /// File加载
        /// StreamingAssets是打进压缩包，不能使用
        /// persistent按正常文件加载
        /// </summary>
        public static string PathPrefix = "file:///";
        
        public static string streamingAssetsPath
        {
            get
            {
                if (Application.platform == RuntimePlatform.Android ||
                    Application.platform == RuntimePlatform.IPhonePlayer)
                {
                    return Application.streamingAssetsPath;
                }
                if (Application.platform == RuntimePlatform.WindowsEditor ||
                    Application.platform == RuntimePlatform.OSXEditor)
                {
                    return PathPrefix + Application.streamingAssetsPath;
                }
                return Application.streamingAssetsPath;
            }
        }
        
        public static string persistentDataPath
        {
            get
            {
                if (Application.platform == RuntimePlatform.Android ||
                    Application.platform == RuntimePlatform.IPhonePlayer ||
                    Application.platform == RuntimePlatform.WindowsEditor ||
                    Application.platform == RuntimePlatform.OSXEditor)
                {
                    return PathPrefix + Application.persistentDataPath;
                }
                return Application.persistentDataPath;
            }
        }

        public static bool IsMobile => Application.platform == RuntimePlatform.Android ||
                                       Application.platform == RuntimePlatform.IPhonePlayer;

        public static bool IsEditor => Application.platform == RuntimePlatform.WindowsEditor ||
                                       Application.platform == RuntimePlatform.LinuxEditor ||
                                       Application.platform == RuntimePlatform.OSXEditor;

        public static bool IsPC => Application.platform == RuntimePlatform.WindowsPlayer ||
                                   Application.platform == RuntimePlatform.OSXPlayer;
    }
}

<|start_filename|>Runtime/UI/Wrap/InputFieldWrapper.cs<|end_filename|>
﻿using System;
using Framework.UI.Core;
using Framework.UI.Wrap.Base;
using TMPro;
using UnityEngine.Events;
using UnityEngine.UI;

namespace Framework.UI.Wrap
{
    public class InputFieldWrapper : BaseWrapper<InputField>, IFieldChangeCb<string>, IComponentEvent<string>
    {
        Action<string> IFieldChangeCb<string>.GetFieldChangeCb()
        {
            return (value) => Component.text = value;
        }

        UnityEvent<string> IComponentEvent<string>.GetComponentEvent()
        {
            return Component.onEndEdit;
        }

        public InputFieldWrapper(InputField component, View view) : base(component, view)
        {
        }
    }
    
    public class TMPInputFieldWrapper : BaseWrapper<TMP_InputField>, IFieldChangeCb<string>, IComponentEvent<string>
    {

        Action<string> IFieldChangeCb<string>.GetFieldChangeCb()
        {
            return (value) => Component.text = value;
        }

        UnityEvent<string> IComponentEvent<string>.GetComponentEvent()
        {
            return Component.onEndEdit;
        }

        public TMPInputFieldWrapper(TMP_InputField component, View view) : base(component, view)
        {
        }
    }
}

<|start_filename|>Runtime/Common/ScriptCollection/Empty4Raycast.cs<|end_filename|>
using UnityEngine.UI;

namespace Framework
{
	/// <inheritdoc />
	/// <summary>
	/// reference from :http://gad.qq.com/article/detail/37846
	/// 替换空 Image 扩大点击区域，降低 Drawcall。
	/// </summary>
	public class Empty4Raycast  : MaskableGraphic
	{
		protected Empty4Raycast()
		{
			useLegacyMeshGeneration = false;
		}

		protected override void OnPopulateMesh(VertexHelper toFill)
		{
			toFill.Clear();
		}
	}
}


<|start_filename|>Runtime/Common/Singleton/SingletonProperty.cs<|end_filename|>
using System;

namespace Framework
{
	public static class SingletonProperty<T> where T : class
	{
		private static T instance;
		private static readonly object @lock = new object();

		public static T Instance
		{
			get
			{
				lock (@lock)
				{
					if (instance == null)
					{
						instance = Activator.CreateInstance<T>();
					}
				}

				return instance;
			}
		}

		public static void Dispose()
		{
			instance = null;
		}
	}
}

<|start_filename|>Runtime/UI/Wrap/SliderWrapper.cs<|end_filename|>
﻿using System;
using Framework.UI.Core;
using Framework.UI.Core.Bind;
using Framework.UI.Wrap.Base;
using UnityEngine.Events;
using UnityEngine.UI;

namespace Framework.UI.Wrap
{
    public class SliderWrapper : BaseWrapper<Slider>, IFieldChangeCb<float>, IComponentEvent<float>
    {
        Action<float> IFieldChangeCb<float>.GetFieldChangeCb()
        {
            return (value) => Component.value = value;
        }

        UnityEvent<float> IComponentEvent<float>.GetComponentEvent()
        {
            return Component.onValueChanged;
        }

        public SliderWrapper(Slider component, View view) : base(component, view)
        {
        }
    }
}

<|start_filename|>Runtime/Manager/AudioManager.cs<|end_filename|>
﻿using System;
using System.Collections.Generic;
using Framework.Assets;
using Framework.Asynchronous;
using UnityEngine;
using Object = UnityEngine.Object;

namespace Framework
{
    public sealed class AudioManager : MonoSingleton<AudioManager>
    {

        /// <summary>
        /// 背景音乐优先级
        /// </summary>
        private int BackgroundPriority = 0;

        /// <summary>
        /// 单通道音效优先级
        /// </summary>
        private int SinglePriority = 10;

        /// <summary>
        /// 多通道音效优先级
        /// </summary>
        private int MultiplePriority = 20;

        /// <summary>
        /// 世界音效优先级
        /// </summary>
        private int WorldPriority = 30;

        private float _backgroundVolume = 0.6f;
        /// <summary>
        /// 背景音乐音量
        /// </summary>
        private float BackgroundVolume
        {
            get => _backgroundVolume;
            set
            {
                _backgroundVolume = value;
                _backgroundAudio.volume = value;
            }
        }
        /// <summary>
        /// 音效音量
        /// </summary>
        public float SoundEffectVolume = 1;

        private AudioSource _backgroundAudio;
        private AudioSource _singleAudio;
        private readonly List<AudioSourcePlayer> _multipleAudio = new List<AudioSourcePlayer>();
        private readonly Dictionary<GameObject, AudioSource> _worldAudio = new Dictionary<GameObject, AudioSource>();
        private bool _isMute;
        private IRes res;

        private void Awake()
        {
            _backgroundAudio = CreateAudioSource("BackgroundAudio", BackgroundPriority, BackgroundVolume);
            _singleAudio = CreateAudioSource("SingleAudio", SinglePriority, SoundEffectVolume);
            res = Res.Create();
        }
        
        private class AudioSourcePlayer : IDisposable
        {
            private AudioSource _audioSource;

            public bool IsPlaying => _audioSource.isPlaying;

            public int Priority
            {
                get => _audioSource.priority;
                set => _audioSource.priority = value;
            }

            public float Volume
            {
                get => _audioSource.volume;
                set => _audioSource.volume = value;
            }

            public bool Mute
            {
                get => _audioSource.mute;
                set => _audioSource.mute = value;
            }

            public AudioSourcePlayer(AudioSource audioSource)
            {
                this._audioSource = audioSource;
            }

            public bool IsSameClip(AudioClip clip)
            {
                return _audioSource.clip == clip;
            }

            public bool IsSameClip(string name)
            {
                return _audioSource.clip.name == name;
            }

            public void SetParams(AudioClip clip, bool isLoop, float speed)
            {
                _audioSource.clip = clip;
                _audioSource.loop = isLoop;
                _audioSource.pitch = speed;
                _audioSource.spatialBlend = 0;
            }

            public void Play()
            {
                _audioSource.Play();
            }

            public void Stop()
            {
                _audioSource.Stop();
            }

            private void Release()
            {
                _audioSource.clip = null;
            }

            public void Dispose()
            {
                Release();
                Object.Destroy(_audioSource.gameObject);
                _audioSource = null;
            }
        }
        
        /// <summary>
        /// 静音
        /// </summary>
        public bool Mute
        {
            get => _isMute;
            set
            {
                _isMute = value;
                _backgroundAudio.mute = value;
                _singleAudio.mute = value;
                foreach (var audio in _multipleAudio)
                {
                    audio.Mute = value;
                }

                foreach (KeyValuePair<GameObject, AudioSource> audio in _worldAudio)
                {
                    audio.Value.mute = value;
                }
            }
        }

        /// <summary>
        /// 播放背景音乐
        /// </summary>
        public async void PlayBackgroundMusic(string clipName, bool isLoop = true, float speed = 1)
        {
            var clip = await res.LoadAssetAsync<AudioClip>(clipName);
            if (_backgroundAudio.isPlaying)
            {
                _backgroundAudio.Stop();
            }

            _backgroundAudio.clip = clip;
            _backgroundAudio.loop = isLoop;
            _backgroundAudio.pitch = speed;
            _backgroundAudio.spatialBlend = 0;
            _backgroundAudio.Play();
        }

        /// <summary>
        /// 暂停播放背景音乐
        /// </summary>
        public void PauseBackgroundMusic(bool isGradual = true)
        {
            if (!_backgroundAudio.isPlaying) return;
            // if (isGradual)
            // {
            //     _backgroundAudio.DOFade(0, 2);
            // }
            // else
            {
                _backgroundAudio.volume = 0;
            }
        }

        /// <summary>
        /// 恢复播放背景音乐
        /// </summary>
        public void UnPauseBackgroundMusic(bool isGradual = true)
        {
            if (!_backgroundAudio.isPlaying) return;
            // if (isGradual)
            // {
            //     _backgroundAudio.DOFade(BackgroundVolume, 2);
            // }
            // else
            {
                _backgroundAudio.volume = BackgroundVolume;
            }
        }

        /// <summary>
        /// 停止播放背景音乐
        /// </summary>
        public void StopBackgroundMusic()
        {
            if (_backgroundAudio.isPlaying)
            {
                _backgroundAudio.Stop();
            }
        }

        /// <summary>
        /// 播放单通道音效
        /// </summary>
        public async void PlaySingleSound(string clipName, bool isLoop = false, float speed = 1)
        {
            var clip = await res.LoadAssetAsync<AudioClip>(clipName);
            if (_singleAudio.isPlaying)
            {
                _singleAudio.Stop();
            }

            _singleAudio.clip = clip;
            _singleAudio.loop = isLoop;
            _singleAudio.pitch = speed;
            _singleAudio.spatialBlend = 0;
            _singleAudio.Play();
        }

        /// <summary>
        /// 暂停播放单通道音效
        /// </summary>
        public void PauseSingleSound(bool isGradual = true)
        {
            if (!_singleAudio.isPlaying) return;
            // if (isGradual)
            // {
            //     _singleAudio.DOFade(0, 2);
            // }
            // else
            {
                _singleAudio.volume = 0;
            }
        }

        /// <summary>
        /// 恢复播放单通道音效
        /// </summary>
        public void UnPauseSingleSound(bool isGradual = true)
        {
            if (!_singleAudio.isPlaying) return;
            // if (isGradual)
            // {
            //     _singleAudio.DOFade(SoundEffectVolume, 2);
            // }
            // else
            {
                _singleAudio.volume = SoundEffectVolume;
            }
        }

        /// <summary>
        /// 停止播放单通道音效
        /// </summary>
        public void StopSingleSound()
        {
            if (_singleAudio.isPlaying)
            {
                _singleAudio.Stop();
            }
        }

        /// <summary>
        /// 播放多通道音效
        /// </summary>
        public async void PlayMultipleSound(string clipName, bool isLoop = false, float speed = 1)
        {
            var clip = await res.LoadAssetAsync<AudioClip>(clipName);
            PlayMultipleSound(clip, isLoop, speed);
        }
        
        /// <summary>
        /// 播放多通道音效
        /// </summary>
        public void PlayMultipleSound(AudioClip clip, bool isLoop = false, float speed = 1)
        {
            var audio = ExtractIdleMultipleAudioSource();
            audio.SetParams(clip, isLoop, speed);
            audio.Play();
        }

        /// <summary>
        /// 停止播放指定的多通道音效
        /// </summary>
        public void StopMultipleSound(string name)
        {
            foreach (var audio in _multipleAudio)
            {
                if (!audio.IsPlaying) continue;
                if (audio.IsSameClip(name))
                {
                    audio.Stop();
                }
            }
        }

        /// <summary>
        /// 停止播放所有多通道音效
        /// </summary>
        public void StopAllMultipleSound()
        {
            foreach (var audio in _multipleAudio)
            {
                if (audio.IsPlaying)
                {
                    audio.Stop();
                }
            }
        }

        /// <summary>
        /// 销毁所有闲置中的多通道音效的音源
        /// </summary>
        public void ClearIdleMultipleAudioSource()
        {
            for (int i = 0; i < _multipleAudio.Count; i++)
            {
                if (_multipleAudio[i].IsPlaying) continue;
                AudioSourcePlayer player = _multipleAudio[i];
                _multipleAudio.RemoveAt(i);
                i -= 1;
                player.Dispose();
            }
        }

        /// <summary>
        /// 播放世界音效
        /// </summary>
        public async void PlayWorldSound(GameObject attachTarget, string clipName, bool isLoop = false, float speed = 1)
        {
            var clip = await res.LoadAssetAsync<AudioClip>(clipName);
            if (_worldAudio.ContainsKey(attachTarget))
            {
                AudioSource audio = _worldAudio[attachTarget];
                if (audio.isPlaying)
                {
                    audio.Stop();
                }

                audio.clip = clip;
                audio.loop = isLoop;
                audio.pitch = speed;
                audio.spatialBlend = 1;
                audio.Play();
            }
            else
            {
                AudioSource audio = AttachAudioSource(attachTarget, WorldPriority, SoundEffectVolume);
                _worldAudio.Add(attachTarget, audio);
                audio.clip = clip;
                audio.loop = isLoop;
                audio.pitch = speed;
                audio.spatialBlend = 1;
                audio.Play();
            }
        }

        /// <summary>
        /// 暂停播放指定的世界音效
        /// </summary>
        public void PauseWorldSound(GameObject attachTarget, bool isGradual = true)
        {
            if (!_worldAudio.ContainsKey(attachTarget)) return;
            AudioSource audio = _worldAudio[attachTarget];
            if (!audio.isPlaying) return;
            // if (isGradual)
            // {
            //     audio.DOFade(0, 2);
            // }
            // else
            {
                audio.volume = 0;
            }
        }

        /// <summary>
        /// 恢复播放指定的世界音效
        /// </summary>
        public void UnPauseWorldSound(GameObject attachTarget, bool isGradual = true)
        {
            if (!_worldAudio.ContainsKey(attachTarget)) return;
            AudioSource audio = _worldAudio[attachTarget];
            if (!audio.isPlaying) return;
            // if (isGradual)
            // {
            //     audio.DOFade(SoundEffectVolume, 2);
            // }
            // else
            {
                audio.volume = SoundEffectVolume;
            }
        }

        /// <summary>
        /// 停止播放所有的世界音效
        /// </summary>
        public void StopAllWorldSound()
        {
            foreach (KeyValuePair<GameObject, AudioSource> audio in _worldAudio)
            {
                if (audio.Value.isPlaying)
                {
                    audio.Value.Stop();
                }
            }
        }

        /// <summary>
        /// 销毁所有闲置中的世界音效的音源
        /// </summary>
        public void ClearIdleWorldAudioSource()
        {
            HashSet<GameObject> removeSet = new HashSet<GameObject>();
            foreach (KeyValuePair<GameObject, AudioSource> audio in _worldAudio)
            {
                if (!audio.Value.isPlaying)
                {
                    removeSet.Add(audio.Key);
                    Object.Destroy(audio.Value);
                }
            }

            foreach (GameObject item in removeSet)
            {
                _worldAudio.Remove(item);
            }
        }

        /// <summary>
        /// 创建一个音源
        /// </summary>
        private AudioSource CreateAudioSource(string name, int priority, float volume)
        {
            GameObject audioObj = new GameObject(name);
            audioObj.transform.SetParent(gameObject.transform);
            audioObj.transform.localPosition = Vector3.zero;
            audioObj.transform.localRotation = Quaternion.identity;
            audioObj.transform.localScale = Vector3.one;
            AudioSource audio = audioObj.AddComponent<AudioSource>();
            audio.playOnAwake = false;
            audio.priority = priority;
            audio.volume = volume;
            audio.mute = _isMute;
            return audio;
        }

        /// <summary>
        /// 创建一个音源包装类
        /// </summary>
        private AudioSourcePlayer CreateAudioSourcePlayer(string name, int priority, float volume)
        {
            var audio = CreateAudioSource(name, priority, volume);
            return new AudioSourcePlayer(audio);
        }

        /// <summary>
        /// 附加一个音源
        /// </summary>
        private AudioSource AttachAudioSource(GameObject target, int priority, float volume)
        {
            AudioSource audio = target.AddComponent<AudioSource>();
            audio.playOnAwake = false;
            audio.priority = priority;
            audio.volume = volume;
            audio.mute = _isMute;
            return audio;
        }

        /// <summary>
        /// 提取闲置中的多通道音源
        /// </summary>
        private AudioSourcePlayer ExtractIdleMultipleAudioSource()
        {
            foreach (var audioSource in _multipleAudio)
            {
                if (!audioSource.IsPlaying)
                {
                    return audioSource;
                }
            }

            var audio = CreateAudioSourcePlayer("MultipleAudio", MultiplePriority, SoundEffectVolume);
            _multipleAudio.Add(audio);
            return audio;
        }

        public void Dispose()
        {
            StopBackgroundMusic();
            StopSingleSound();
            StopAllMultipleSound();
            StopAllWorldSound();
            res.Release();
        }
    }
}

<|start_filename|>Runtime/Asynchronous/ProgressTask.cs<|end_filename|>
﻿/*
 * MIT License
 *
 * Copyright (c) 2018 <NAME>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of 
 * this software and associated documentation files (the "Software"), to deal in 
 * the Software without restriction, including without limitation the rights to 
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
 * of the Software, and to permit persons to whom the Software is furnished to do so, 
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all 
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
 * SOFTWARE.
 */

using System;
using System.Threading;
using System.Collections;
using Framework.Execution;

namespace Framework.Asynchronous
{
    public class ProgressTask<TProgress> : IProgressTask<TProgress>
    {
        private readonly Action _action;

        private Action _preCallbackOnMainThread;
        private Action _preCallbackOnWorkerThread;

        private Action _postCallbackOnMainThread;
        private Action _postCallbackOnWorkerThread;

        private Action<TProgress> _progressCallbackOnMainThread;
        private Action<TProgress> _progressCallbackOnWorkerThread;

        private Action<Exception> _errorCallbackOnMainThread;
        private Action<Exception> _errorCallbackOnWorkerThread;

        private Action _finishCallbackOnMainThread;
        private Action _finishCallbackOnWorkerThread;

        private int _running;
        private readonly ProgressResult<TProgress> _result;

        public ProgressTask(Action<IProgressPromise<TProgress>> task, bool runOnMainThread = false,
            bool cancelable = false)
        {
            if (task == null)
                throw new ArgumentNullException();

            this._result = new ProgressResult<TProgress>(!runOnMainThread && cancelable);
            this._result.Callbackable().OnProgressCallback(OnProgressChanged);
            if (runOnMainThread)
            {
                this._action = WrapAction(() =>
                {
                    Executors.RunOnMainThread(() => task(_result), true);
                    _result.Synchronized().WaitForResult();
                });
            }
            else
            {
                this._action = WrapAction(() =>
                {
                    task(_result);
                    _result.Synchronized().WaitForResult();
                });
            }
        }

        /// <summary>
        /// run on main thread.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="cancelable"></param>
        public ProgressTask(Func<IProgressPromise<TProgress>, IEnumerator> task, bool cancelable = false)
        {
            if (task == null)
                throw new ArgumentNullException();

            this._result = new ProgressResult<TProgress>(cancelable);
            this._result.Callbackable().OnProgressCallback(OnProgressChanged);
            this._action = WrapAction(() =>
            {
                Executors.RunOnCoroutine(task(this._result), this._result);
                this._result.Synchronized().WaitForResult();
            });
        }

        public virtual object Result => this._result.Result;

        public virtual Exception Exception => this._result.Exception;

        public virtual bool IsDone => this._result.IsDone && this._running == 0;

        public virtual bool IsCancelled => this._result.IsCancelled;

        public virtual TProgress Progress => this._result.Progress;

        protected virtual Action WrapAction(Action action)
        {
            void WrapFunc()
            {
                try
                {
                    try
                    {
                        _preCallbackOnWorkerThread?.Invoke();
                    }
                    catch (Exception e)
                    {
                        Log.Warning(e);
                    }

                    if (this._result.IsCancellationRequested)
                    {
                        this._result.SetCancelled();
                        return;
                    }

                    action();
                }
                catch (Exception e)
                {
                    this._result.SetException(e);
                }
                finally
                {
                    try
                    {
                        if (this.Exception != null)
                        {
                            if (this._errorCallbackOnMainThread != null)
                                Executors.RunOnMainThread(() => this._errorCallbackOnMainThread(this.Exception), true);

                            _errorCallbackOnWorkerThread?.Invoke(this.Exception);
                        }
                        else
                        {
                            if (this._postCallbackOnMainThread != null)
                                Executors.RunOnMainThread(this._postCallbackOnMainThread, true);

                            _postCallbackOnWorkerThread?.Invoke();
                        }
                    }
                    catch (Exception e)
                    {
                        Log.Warning(e);
                    }

                    try
                    {
                        if (this._finishCallbackOnMainThread != null)
                            Executors.RunOnMainThread(this._finishCallbackOnMainThread, true);

                        _finishCallbackOnWorkerThread?.Invoke();
                    }
                    catch (Exception e)
                    {
                        Log.Warning(e);
                    }

                    Interlocked.Exchange(ref this._running, 0);
                }
            }

            return WrapFunc;
        }

        protected virtual IEnumerator DoUpdateProgressOnMainThread()
        {
            while (!_result.IsDone)
            {
                try
                {
                    _progressCallbackOnMainThread?.Invoke(this._result.Progress);
                }
                catch (Exception e)
                {
                    Log.Warning(e);
                }

                yield return null;
            }
        }

        protected virtual void OnProgressChanged(TProgress progress)
        {
            try
            {
                if (this._result.IsDone || this._progressCallbackOnWorkerThread == null)
                    return;

                this._progressCallbackOnWorkerThread(progress);
            }
            catch (Exception e)
            {
                Log.Warning(e);
            }
        }

        public virtual bool Cancel()
        {
            return this._result.Cancel();
        }

        public virtual IProgressCallbackable<TProgress> Callbackable()
        {
            return _result.Callbackable();
        }

        ICallbackable IAsyncResult.Callbackable()
        {
            return (_result as IAsyncResult).Callbackable();
        }

        public virtual ISynchronizable Synchronized()
        {
            return _result.Synchronized();
        }

        public virtual object WaitForDone()
        {
            return Executors.WaitWhile(() => !IsDone);
        }

        public IProgressTask<TProgress> OnPreExecute(Action callback, bool runOnMainThread = true)
        {
            if (runOnMainThread)
                this._preCallbackOnMainThread += callback;
            else
                this._preCallbackOnWorkerThread += callback;
            return this;
        }

        public IProgressTask<TProgress> OnPostExecute(Action callback, bool runOnMainThread = true)
        {
            if (runOnMainThread)
                this._postCallbackOnMainThread += callback;
            else
                this._postCallbackOnWorkerThread += callback;
            return this;
        }

        public IProgressTask<TProgress> OnError(Action<Exception> callback, bool runOnMainThread = true)
        {
            if (runOnMainThread)
                this._errorCallbackOnMainThread += callback;
            else
                this._errorCallbackOnWorkerThread += callback;
            return this;
        }

        public IProgressTask<TProgress> OnProgressUpdate(Action<TProgress> callback, bool runOnMainThread = true)
        {
            if (runOnMainThread)
                this._progressCallbackOnMainThread += callback;
            else
                this._progressCallbackOnWorkerThread += callback;
            return this;
        }

        public IProgressTask<TProgress> OnFinish(Action callback, bool runOnMainThread = true)
        {
            if (runOnMainThread)
                this._finishCallbackOnMainThread += callback;
            else
                this._finishCallbackOnWorkerThread += callback;
            return this;
        }

        public IProgressTask<TProgress> Start(int delay)
        {
            if (delay <= 0)
                return this.Start();

            Executors.RunAsync(() =>
            {
#if NETFX_CORE
                Task.Delay(delay).Wait();
#else
                Thread.Sleep(delay);
#endif
                if (this.IsDone || this._running == 1)
                    return;

                this.Start();
            });
            return this;
        }

        public IProgressTask<TProgress> Start()
        {
            if (this.IsDone)
            {
                Log.Warning("The task has been done!");
                return this;
            }

            if (Interlocked.CompareExchange(ref this._running, 1, 0) == 1)
            {
                Log.Warning("The task is running!");
                return this;
            }

            try
            {
                if (this._preCallbackOnMainThread != null)
                    Executors.RunOnMainThread(this._preCallbackOnMainThread, true);

                if (this._progressCallbackOnMainThread != null)
                    Executors.RunOnCoroutineNoReturn(DoUpdateProgressOnMainThread());
            }
            catch (Exception e)
            {
                Log.Warning(e);
            }

            Executors.RunAsync(this._action);

            return this;
        }


    }

    public class ProgressTask<TProgress, TResult> : IProgressTask<TProgress, TResult>
    {
        private readonly Action _action;

        private Action _preCallbackOnMainThread;
        private Action _preCallbackOnWorkerThread;

        private Action<TResult> _postCallbackOnMainThread;
        private Action<TResult> _postCallbackOnWorkerThread;

        private Action<TProgress> _progressCallbackOnMainThread;
        private Action<TProgress> _progressCallbackOnWorkerThread;

        private Action<Exception> _errorCallbackOnMainThread;
        private Action<Exception> _errorCallbackOnWorkerThread;

        private Action _finishCallbackOnMainThread;
        private Action _finishCallbackOnWorkerThread;

        private int _running;
        private readonly ProgressResult<TProgress, TResult> _result;

        public ProgressTask(Action<IProgressPromise<TProgress, TResult>> task, bool runOnMainThread,
            bool cancelable = false)
        {
            if (task == null)
                throw new ArgumentNullException();

            this._result = new ProgressResult<TProgress, TResult>(!runOnMainThread && cancelable);
            this._result.Callbackable().OnProgressCallback(OnProgressChanged);

            if (runOnMainThread)
            {
                this._action = WrapAction(() =>
                {
                    Executors.RunOnMainThread(() => task(_result), true);
                    return this._result.Synchronized().WaitForResult();
                });
            }
            else
            {
                this._action = WrapAction(() =>
                {
                    task(_result);
                    return this._result.Synchronized().WaitForResult();
                });
            }
        }

        public ProgressTask(Func<IProgressPromise<TProgress, TResult>, IEnumerator> task, bool cancelable = false)
        {
            if (task == null)
                throw new ArgumentNullException();

            this._result = new ProgressResult<TProgress, TResult>(cancelable);
            this._result.Callbackable().OnProgressCallback(OnProgressChanged);
            this._action = WrapAction(() =>
            {
                Executors.RunOnCoroutine(task(this._result), this._result);
                return this._result.Synchronized().WaitForResult();
            });
        }

        public virtual TResult Result => this._result.Result;

        object Asynchronous.IAsyncResult.Result => this._result.Result;

        public virtual Exception Exception => this._result.Exception;

        public virtual bool IsDone => this._result.IsDone && this._running == 0;

        public virtual bool IsCancelled => this._result.IsCancelled;

        public virtual TProgress Progress => this._result.Progress;

        protected virtual Action WrapAction(Func<TResult> action)
        {
            void WrapAction()
            {
                try
                {
                    try
                    {
                        if (this._preCallbackOnWorkerThread != null) this._preCallbackOnWorkerThread();
                    }
                    catch (Exception e)
                    {
                        Log.Warning(e);
                    }

                    if (this._result.IsCancellationRequested)
                    {
                        this._result.SetCancelled();
                        return;
                    }

                    TResult obj = action();
                    this._result.SetResult(obj);
                }
                catch (Exception e)
                {
                    this._result.SetException(e);
                }
                finally
                {
                    try
                    {
                        if (this.Exception != null)
                        {
                            if (this._errorCallbackOnMainThread != null)
                                Executors.RunOnMainThread(() => this._errorCallbackOnMainThread(this.Exception), true);

                            _errorCallbackOnWorkerThread?.Invoke(this.Exception);
                        }
                        else
                        {
                            if (this._postCallbackOnMainThread != null)
                                Executors.RunOnMainThread(() => this._postCallbackOnMainThread(this.Result), true);

                            _postCallbackOnWorkerThread?.Invoke(this.Result);
                        }
                    }
                    catch (Exception e)
                    {
                        Log.Warning(e);
                    }

                    try
                    {
                        if (this._finishCallbackOnMainThread != null)
                            Executors.RunOnMainThread(this._finishCallbackOnMainThread, true);

                        _finishCallbackOnWorkerThread?.Invoke();
                    }
                    catch (Exception e)
                    {
                        Log.Warning(e);
                    }

                    Interlocked.Exchange(ref this._running, 0);
                }
            }

            return WrapAction;
        }

        protected virtual IEnumerator DoUpdateProgressOnMainThread()
        {
            while (!_result.IsDone)
            {
                try
                {
                    _progressCallbackOnMainThread?.Invoke(this._result.Progress);
                }
                catch (Exception e)
                {
                    Log.Warning(e);
                }

                yield return null;
            }
        }

        protected virtual void OnProgressChanged(TProgress progress)
        {
            try
            {
                if (this._result.IsDone || this._progressCallbackOnWorkerThread == null)
                    return;

                this._progressCallbackOnWorkerThread(progress);
            }
            catch (Exception e)
            {
                Log.Warning(e);
            }
        }

        public virtual bool Cancel()
        {
            return this._result.Cancel();
        }

        public virtual IProgressCallbackable<TProgress, TResult> Callbackable()
        {
            return _result.Callbackable();
        }

        public virtual ISynchronizable<TResult> Synchronized()
        {
            return _result.Synchronized();
        }

        ICallbackable IAsyncResult.Callbackable()
        {

            return (_result as IAsyncResult).Callbackable();
        }

        ICallbackable<TResult> IAsyncResult<TResult>.Callbackable()
        {
            return (_result as IAsyncResult<TResult>).Callbackable();
        }

        IProgressCallbackable<TProgress> IProgressResult<TProgress>.Callbackable()
        {
            return (_result as IProgressResult<TProgress>).Callbackable();
        }

        ISynchronizable IAsyncResult.Synchronized()
        {
            return (_result as IAsyncResult).Synchronized();
        }

        public virtual object WaitForDone()
        {
            return Executors.WaitWhile(() => !IsDone);
        }

        public IProgressTask<TProgress, TResult> OnPreExecute(Action callback, bool runOnMainThread = true)
        {
            if (runOnMainThread)
                this._preCallbackOnMainThread += callback;
            else
                this._preCallbackOnWorkerThread += callback;
            return this;
        }

        public IProgressTask<TProgress, TResult> OnPostExecute(Action<TResult> callback, bool runOnMainThread = true)
        {
            if (runOnMainThread)
                this._postCallbackOnMainThread += callback;
            else
                this._postCallbackOnWorkerThread += callback;
            return this;
        }

        public IProgressTask<TProgress, TResult> OnError(Action<Exception> callback, bool runOnMainThread = true)
        {
            if (runOnMainThread)
                this._errorCallbackOnMainThread += callback;
            else
                this._errorCallbackOnWorkerThread += callback;
            return this;
        }

        public IProgressTask<TProgress, TResult> OnProgressUpdate(Action<TProgress> callback,
            bool runOnMainThread = true)
        {
            if (runOnMainThread)
                this._progressCallbackOnMainThread += callback;
            else
                this._progressCallbackOnWorkerThread += callback;
            return this;
        }

        public IProgressTask<TProgress, TResult> OnFinish(Action callback, bool runOnMainThread = true)
        {
            if (runOnMainThread)
                this._finishCallbackOnMainThread += callback;
            else
                this._finishCallbackOnWorkerThread += callback;
            return this;
        }

        public IProgressTask<TProgress, TResult> Start(int delay)
        {
            if (delay <= 0)
                return this.Start();

            Executors.RunAsync(() =>
            {
                Thread.Sleep(delay);
                if (this.IsDone || this._running == 1)
                    return;

                this.Start();
            });
            return this;
        }

        public IProgressTask<TProgress, TResult> Start()
        {
            if (this.IsDone)
            {
                Log.Warning("The task has been done!");
                return this;
            }

            if (Interlocked.CompareExchange(ref this._running, 1, 0) == 1)
            {
                Log.Warning("The task is running!");
                return this;
            }

            try
            {
                if (this._preCallbackOnMainThread != null)
                    Executors.RunOnMainThread(this._preCallbackOnMainThread, true);

                if (this._progressCallbackOnMainThread != null)
                    Executors.RunOnCoroutineNoReturn(DoUpdateProgressOnMainThread());
            }
            catch (Exception e)
            {
                Log.Warning(e);
            }

            Executors.RunAsync(this._action);
            return this;
        }
    }
}


<|start_filename|>Runtime/UI/Core/Bind/BindDic.cs<|end_filename|>
﻿using System.Collections.Specialized;
using Framework.UI.Wrap.Base;

namespace Framework.UI.Core.Bind
{
    // public class BindDic<TComponent,TKey, TValue> : BaseBind
    // {
    //     private readonly TComponent _component;
    //     private readonly ObservableDictionary<TKey, TValue> _dictionary;
    //     private IBindDic _bindDic;
    //
    //     public BindDic( TComponent view, ObservableDictionary<TKey, TValue> dictionary)
    //     {
    //         _component = view;
    //         _dictionary = dictionary;
    //         InitEvent();
    //         InitCpntValue();
    //     }
    //
    //     private void InitCpntValue()
    //     {
    //         _bindDic.GetBindDicFunc();
    //         foreach (var value in _dictionary)
    //         {
    //             _bindDic.GetBindDicFunc()( this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, value));
    //         }
    //     }
    //
    //     private void InitEvent()
    //     {
    //         var bind = BindTool.GetDefaultWrapper(_component);
    //         _bindDic = _bindDic ?? _component as IBindDic ?? bind as IBindDic;
    //         Log.Assert(_bindDic != null);
    //         _dictionary.CollectionChanged += _bindDic.GetBindDicFunc();
    //     }
    //
    //     public override void ClearBind()
    //     {
    //         _dictionary.ClearListener();
    //     }
    // }
}

<|start_filename|>Runtime/UI/Core/ViewModel.cs<|end_filename|>
namespace Framework.UI.Core
{
    public abstract class ViewModel
    {
        public virtual void OnViewDestroy()
        {
        }
    }
}

<|start_filename|>Runtime/Execution/ThreadTimerExecutor.cs<|end_filename|>
﻿/*
 * MIT License
 *
 * Copyright (c) 2018 <NAME>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of 
 * this software and associated documentation files (the "Software"), to deal in 
 * the Software without restriction, including without limitation the rights to 
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
 * of the Software, and to permit persons to whom the Software is furnished to do so, 
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all 
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
 * SOFTWARE.
 */

using System;
using System.Collections.Generic;
using System.Threading;
using Framework.Asynchronous;
using JetBrains.Annotations;
using IAsyncResult = Framework.Asynchronous.IAsyncResult;

namespace Framework.Execution
{
    public class ThreadTimerExecutor : AbstractExecutor, ITimerExecutor
    {
        private readonly IComparer<IDelayTask> _comparer = new ComparerImpl<IDelayTask>();
        private readonly List<IDelayTask> _queue = new List<IDelayTask>();
        private readonly object _lock = new object();
        private bool _running;

        public ThreadTimerExecutor()
        {
        }

        public void Start()
        {
            if (this._running)
                return;

            this._running = true;
            Executors.RunAsync(() =>
            {
                while (_running)
                {
                    IDelayTask task;
                    lock (_lock)
                    {
                        if (_queue.Count <= 0)
                        {
                            Monitor.Wait(_lock);
                            continue;
                        }

                        task = _queue[0];
                        if (task.Delay.Ticks > 0)
                        {
                            Monitor.Wait(_lock, task.Delay);
                            continue;
                        }

                        _queue.RemoveAt(0);
                    }

                    task.Run();
                }
            });
        }

        public void Stop()
        {
            if (!this._running)
                return;

            lock (_lock)
            {
                this._running = false;
                Monitor.PulseAll(_lock);
            }

            List<IDelayTask> list = new List<IDelayTask>(this._queue);
            foreach (IDelayTask task in list)
            {
                if (task != null && !task.IsDone)
                    task.Cancel();
            }

            this._queue.Clear();
        }

        private void Add(IDelayTask task)
        {

            lock (_lock)
            {
                _queue.Add(task);
                _queue.Sort(_comparer);
                Monitor.PulseAll(_lock);
            }
        }

        private bool Remove(IDelayTask task)
        {
            lock (_lock)
            {
                if (_queue.Remove(task))
                {
                    _queue.Sort(_comparer);
                    Monitor.PulseAll(_lock);
                    return true;
                }
            }

            return false;
        }

        protected virtual void Check()
        {
            if (!this._running)
                throw new Exception("The ScheduledExecutor isn't started.");
        }

        public virtual Asynchronous.IAsyncResult Delay(Action command, long delay)
        {
            return Delay(command, GetTimeSpan(delay).Value);
        }

        public virtual Asynchronous.IAsyncResult Delay(Action command, TimeSpan delay)
        {
            this.Check();
            return new OneTimeDelayTask(this, command, delay);
        }

        public virtual IAsyncResult<TResult> Delay<TResult>(Func<TResult> command, long delay)
        {
            return Delay(command, GetTimeSpan(delay).Value);
        }

        public virtual IAsyncResult<TResult> Delay<TResult>(Func<TResult> command, TimeSpan delay)
        {
            this.Check();
            return new OneTimeDelayTask<TResult>(this, command, delay);
        }

        public virtual Asynchronous.IAsyncResult FixedRate(Action command, long initialDelay, long period)
        {
            return FixedRate(command, GetTimeSpan(initialDelay).Value, GetTimeSpan(period).Value);
        }

        public virtual Asynchronous.IAsyncResult FixedRate(Action command, TimeSpan initialDelay,
            TimeSpan period)
        {
            this.Check();
            return new FixedRateDelayTask(this, command, initialDelay, period);
        }

        public IAsyncResult FixedRateAtDuration(Action<long> fixedUpdateCommand, [CanBeNull] Action endCommand = null, long? initialDelay = null, long? period = null,
            long? duration = null)
        {
            return this.FixedRateAtDuration(fixedUpdateCommand, endCommand, GetTimeSpan(initialDelay),
                GetTimeSpan(period), GetTimeSpan(duration));
        }

        public IAsyncResult FixedRateAtDuration(Action<long> fixedUpdateCommand, [CanBeNull] Action endCommand = null, TimeSpan? initialDelay = null, TimeSpan? period = null,
            TimeSpan? duration = null)
        {
            Check();
            return new DurationFixedRateTask(this, fixedUpdateCommand, endCommand, initialDelay, period, duration);
        }
        
        private TimeSpan? GetTimeSpan(long? milliseconds)
        {
            if(milliseconds == null) return null;
            return new TimeSpan(milliseconds.Value * TimeSpan.TicksPerMillisecond);
        }

        public virtual void Dispose()
        {
            this.Stop();
        }

        interface IDelayTask : Asynchronous.IAsyncResult
        {
            TimeSpan Delay { get; }

            void Run();
        }

        class OneTimeDelayTask : AsyncResult, IDelayTask
        {
            private readonly long _startTime;
            private TimeSpan _delay;
            private readonly Action _wrappedAction;
            private readonly ThreadTimerExecutor _executor;

            public OneTimeDelayTask(ThreadTimerExecutor executor, Action command, TimeSpan delay) : base(true)
            {
                this._startTime = DateTime.Now.Ticks;
                this._delay = delay;
                this._executor = executor;
                this._wrappedAction = () =>
                {
                    try
                    {
                        if (this.IsDone)
                        {
                            return;
                        }

                        if (this.IsCancellationRequested)
                        {
                            this.SetCancelled();
                        }
                        else
                        {
                            command();
                            this.SetResult();
                        }
                    }
                    catch (Exception e)
                    {
                        this.SetException(e);
                    }
                };
                this._executor.Add(this);
            }

            public virtual TimeSpan Delay => new TimeSpan(_startTime + _delay.Ticks - DateTime.Now.Ticks);

            public override bool Cancel()
            {
                if (this.IsDone)
                    return false;

                if (!this._executor.Remove(this))
                    return false;

                this.CancellationRequested = true;
                this.SetCancelled();
                return true;
            }

            public virtual void Run()
            {
                try
                {
                    Executors.RunAsync(() => this._wrappedAction());
                }
                catch (Exception)
                {
                }
            }
        }

        class OneTimeDelayTask<TResult> : AsyncResult<TResult>, IDelayTask
        {
            private readonly long _startTime;
            private TimeSpan _delay;
            private readonly Action _wrappedAction;
            private readonly ThreadTimerExecutor _executor;

            public OneTimeDelayTask(ThreadTimerExecutor executor, Func<TResult> command, TimeSpan delay)
            {
                this._startTime = DateTime.Now.Ticks;
                this._delay = delay;
                this._executor = executor;
                this._wrappedAction = () =>
                {
                    try
                    {
                        if (this.IsDone)
                        {
                            return;
                        }

                        if (this.IsCancellationRequested)
                        {
                            this.SetCancelled();
                        }
                        else
                        {
                            this.SetResult(command());
                        }
                    }
                    catch (Exception e)
                    {
                        this.SetException(e);
                    }
                };
                this._executor.Add(this);
            }

            public virtual TimeSpan Delay => new TimeSpan(_startTime + _delay.Ticks - DateTime.Now.Ticks);

            public override bool Cancel()
            {
                if (this.IsDone)
                    return false;

                if (!this._executor.Remove(this))
                    return false;

                this.CancellationRequested = true;
                this.SetCancelled();
                return true;
            }

            public virtual void Run()
            {
                try
                {
                    Executors.RunAsync(() => this._wrappedAction());
                }
                catch (Exception)
                {
                }
            }
        }

        class FixedRateDelayTask : AsyncResult, IDelayTask
        {
            private readonly long _startTime;
            private TimeSpan _initialDelay;
            private TimeSpan _period;
            private readonly ThreadTimerExecutor _executor;
            private readonly Action _wrappedAction;
            private int _count = 0;

            public FixedRateDelayTask(ThreadTimerExecutor executor, Action command, TimeSpan initialDelay,
                TimeSpan period) : base()
            {
                this._startTime = DateTime.Now.Ticks;
                this._initialDelay = initialDelay;
                this._period = period;
                this._executor = executor;

                this._wrappedAction = () =>
                {
                    try
                    {
                        if (this.IsDone)
                            return;

                        if (this.IsCancellationRequested)
                        {
                            this.SetCancelled();
                        }
                        else
                        {
                            Interlocked.Increment(ref _count);
                            this._executor.Add(this);
                            command();
                        }
                    }
                    catch (Exception)
                    {
                    }
                };
                this._executor.Add(this);
            }

            public virtual TimeSpan Delay => new TimeSpan(_startTime + _initialDelay.Ticks + _period.Ticks * _count - DateTime.Now.Ticks);

            public override bool Cancel()
            {
                if (this.IsDone)
                    return false;

                this._executor.Remove(this);
                this.CancellationRequested = true;
                this.SetCancelled();
                return true;
            }

            public virtual void Run()
            {
                try
                {
                    Executors.RunAsync(() => this._wrappedAction());
                }
                catch (Exception)
                {
                }
            }
        }
        
        class DurationFixedRateTask : AsyncResult, IDelayTask
        {
            private readonly long _startTime;
            private TimeSpan _initialDelay;
            private TimeSpan _period;
            private TimeSpan _timer;
            private readonly ThreadTimerExecutor _executor;
            private int _count;
            private readonly Action _wrappedAction;
            private readonly Action _endCommand;

            public DurationFixedRateTask(ThreadTimerExecutor executor, Action<long> fixedUpdateCommand,
                Action endCommand, TimeSpan? initialDelay, TimeSpan? period, TimeSpan? duration) : base()
            {
                this._startTime = DateTime.Now.Ticks;
                this._initialDelay = initialDelay ?? TimeSpan.Zero;
                this._period = period ?? TimeSpan.FromMilliseconds(10);
                this._executor = executor;
                this._endCommand = endCommand;
                this._executor.Add(this);

                this._wrappedAction = () =>
                {
                    try
                    {
                        if (this.IsDone)
                            return;

                        if (this.IsCancellationRequested)
                        {
                            this.SetCancelled();
                        }
                        else
                        {
                            if (_count >= 1)
                                _timer += _period;
                            if (duration.HasValue && _timer >= duration)
                            {
                                Cancel();
                            }
                            fixedUpdateCommand((long) _timer.TotalMilliseconds);
                            this._executor.Add(this);
                            Interlocked.Increment(ref _count);
                        }
                    }
                    catch (Exception e)
                    {
                        Log.Warning(e);
                    }
                };
            }

            public virtual TimeSpan Delay =>
                new TimeSpan(_startTime + _initialDelay.Ticks + _period.Ticks * _count - DateTime.Now.Ticks);

            public override bool Cancel()
            {
                if (this.IsDone)
                    return false;
                _endCommand();
                this._executor.Remove(this);
                this.CancellationRequested = true;
                this.SetCancelled();
                return true;
            }

            public virtual void Run()
            {
                try
                {
                    Executors.RunAsync(() => this._wrappedAction());
                }
                catch (Exception)
                {
                }
            }
        }

        class ComparerImpl<T> : IComparer<T> where T : IDelayTask
        {
            public int Compare(T x, T y)
            {
                if (x.Delay.Ticks == y.Delay.Ticks)
                    return 0;

                return x.Delay.Ticks > y.Delay.Ticks ? 1 : -1;
            }
        }
    }
}


<|start_filename|>Runtime/Tool/MathHelper.cs<|end_filename|>
using System.Collections.Generic;
using Random = UnityEngine.Random;

namespace Framework.Helper
{
	public static class MathHelper
	{
		private struct MinAndMax
		{
			public int min;
			public int max;

			public MinAndMax(int min, int max)
			{
				this.min = min;
				this.max = max;
			}
		}

		/// <summary>
		/// 根据概率得到随机的索引 索引是从0开始
		/// 传入的是百分之的概率 50代表百分之50
		/// [20,30,50] 总和需要是100
		/// </summary>
		public static int GetRandomIndex(params int[] muls)
		{
			List<MinAndMax> tempList = new List<MinAndMax>(muls.Length);
			for (int i = 0; i < muls.Length; i++)
			{
				int min = 0, max = 0;
				for (int j = 0; j < i; j++)
				{
					min += muls[j];
				}

				max = min + muls[i];
				tempList.Add(new MinAndMax(min, max));
			}

			int rand = Random.Range(1, 101);
			foreach (MinAndMax item in tempList)
			{
				if (rand >= item.min && rand <= item.max)
					return tempList.IndexOf(item);
			}

			return -1;
		}
	}
}

<|start_filename|>Runtime/UI/Wrap/DefaultBindList.cs<|end_filename|>
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using Framework.UI.Wrap.Base;
using UnityEngine;
using Object = UnityEngine.Object;

namespace Framework.UI.Wrap
{
    public class DefaultBindList<TComponent, TVm> : IBindList<TVm> where TComponent :  Component
    {
        private List<TComponent> _allObj = new List<TComponent>();
        private TComponent _template;
        private Transform _parent;
        private Action<TComponent, TVm> _onCreate;
        private Action<TComponent, TVm> _onDestroy;

        public DefaultBindList(TComponent template, Action<TComponent, TVm> onCreate, Action<TComponent, TVm> onDestroy)
        {
            _template = template;
            _parent = template.transform.parent;
            _onCreate = onCreate;
            _onDestroy = onDestroy;
        }

        public Action<NotifyCollectionChangedAction, TVm, int> GetBindListFunc()
        {
            return BindListFunc;
        }

        private void BindListFunc
            (NotifyCollectionChangedAction type, TVm obj, int index)
        {
            switch (type)
            {
                case NotifyCollectionChangedAction.Add:
                    var gen = Object.Instantiate(_template, _parent, false);
                    _onCreate?.Invoke(gen, obj);
                    _allObj.Add(gen);
                    break;
                case NotifyCollectionChangedAction.Remove:
                    _onDestroy?.Invoke(_allObj[index], obj);
                    Object.Destroy(_allObj[index].gameObject);
                    _allObj.RemoveAt(index);
                    break;
                case NotifyCollectionChangedAction.Replace:
                    Log.Warning("default bind list not support replace");
                    break;
                case NotifyCollectionChangedAction.Reset:
                    _allObj.ForEach(com => Object.Destroy(com.gameObject));
                    _allObj.Clear();
                    break;
                case NotifyCollectionChangedAction.Move: break;
                default: throw new ArgumentOutOfRangeException(nameof(type), type, null);
            }
        }

#pragma warning disable 693
        public static DefaultBindList<Component, TVm> Create<TObject,TVm>(Object component, Action<TObject, TVm> onCreate, Action<TObject, TVm> onDestroy) where TObject : Object
#pragma warning restore 693
        {
            Log.Assert(typeof(TObject).IsSubclassOf(typeof(Component)), "typeof(TObject) Is not SubclassOf(typeof(Component))");
            return new DefaultBindList<Component, TVm>(component as Component, (component1, vm) =>
            {
                onCreate?.Invoke(component1 as TObject, vm);
            }, (component1, vm) =>
            {
                onDestroy?.Invoke(component1 as TObject, vm);
            });
        }
    }
}

<|start_filename|>Runtime/UI/Wrap/DropdownWrapper.cs<|end_filename|>
using System;
using System.Collections.Specialized;
using Framework.UI.Core;
using Framework.UI.Wrap.Base;
using UnityEngine.Events;
using UnityEngine.UI;

namespace Framework.UI.Wrap
{
    public class DropdownWrapper : BaseWrapper<Dropdown>, IFieldChangeCb<int>, IComponentEvent<int>,
        IBindList<Dropdown.OptionData>
    {

        public Action<int> GetFieldChangeCb()
        {
            return (index) => Component.value = index;
        }

        public UnityEvent<int> GetComponentEvent()
        {
            return Component.onValueChanged;
        }

        public Action<NotifyCollectionChangedAction, Dropdown.OptionData, int> GetBindListFunc()
        {
            return BindListFunc;
        }
        
        private void BindListFunc
            (NotifyCollectionChangedAction type, Dropdown.OptionData data, int index)
        {
            switch (type)
            {
                case NotifyCollectionChangedAction.Add:
                    Component.options.Insert(index, data);
                    break;
                case NotifyCollectionChangedAction.Remove:
                    Component.options.RemoveAt(index);
                    break;
                case NotifyCollectionChangedAction.Replace:
                    Component.options[index] = data;
                    break;
                case NotifyCollectionChangedAction.Reset:
                    Clear();
                    break;
                case NotifyCollectionChangedAction.Move: break;
                default: throw new ArgumentOutOfRangeException(nameof(type), type, null);
            }
        }

        private void Clear()
        {
            Component.options.Clear();
        }

        public DropdownWrapper(Dropdown component, View view) : base(component, view)
        {
        }
    }
}

<|start_filename|>Runtime/Tool/DebugUILine.cs<|end_filename|>
﻿using System;
using UnityEngine;
using UnityEngine.UI;

#if UNITY_EDITOR
namespace Framework
{
    public class DebugUILine : MonoBehaviour
    {
        static Vector3[] fourCorners = new Vector3[4];

        void OnDrawGizmos()
        {
            foreach (MaskableGraphic g in FindObjectsOfType<MaskableGraphic>())
            {
                if (g.raycastTarget)
                {
                    RectTransform rectTransform = g.transform as RectTransform;
                    rectTransform.GetWorldCorners(fourCorners);
                    Gizmos.color = Color.blue;
                    for (int i = 0; i < 4; i++)
                        Gizmos.DrawLine(fourCorners[i], fourCorners[(i + 1) % 4]);

                }
            }
        }
    }
}
#endif


<|start_filename|>Runtime/UI/Component/RefreshScrollRect.cs<|end_filename|>
﻿using System;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
 
public class RefreshScrollRect : ScrollRect {
 
    //高度 往下拉是负数   往上拉是正数
    float f = -300f;
    //是否刷新
    bool isRef = false;
    //是否处于拖动
    bool isDrag = false;
    bool isUp = false;
    //如果满足刷新条件 执行的方法
    public Action PageUp;
    public Action PageDown;
    private RectTransform rect=>GetComponentInChildren<ContentSizeFitter>().GetComponent<RectTransform>();
 
    protected override void Awake()
    {
        base.Awake();
        onValueChanged.AddListener(ScrollValueChanged);
    }
 
    /// <summary>
    /// 当ScrollRect被拖动时
    /// </summary>
    /// <param name="vector">被拖动的距离与Content的大小比例</param>
    void ScrollValueChanged(Vector2 vector)
    {
        //如果不拖动 当然不执行之下的代码
        if (!isDrag)
            return;
        //这个就是Content
        //如果拖动的距离大于给定的值
        if (f > rect.rect.height * vector.y)
        {
            isRef = true;
            isUp = true;
        }
        else if(-f+rect.rect.height<rect.rect.height * vector.y)
        {
            isRef = true;
            isUp = false;
        }
        else
        {
            isRef = false;
        }
    }
 
    public override void OnBeginDrag(PointerEventData eventData)
    {
        base.OnBeginDrag(eventData);
        isDrag = true;
    }
 
    public override void OnEndDrag(PointerEventData eventData)
    {
        base.OnEndDrag(eventData);
        if (isRef)
        {
            if (isUp)
            {
                PageUp?.Invoke();
            }
            else
            {
                PageDown?.Invoke();
            }
        }
        isRef = false;
        isDrag = false;
    }
 
}

<|start_filename|>Runtime/Asynchronous/CoroutineAwaiter.cs<|end_filename|>
﻿/*
 * MIT License
 *
 * Copyright (c) 2018 <NAME>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of 
 * this software and associated documentation files (the "Software"), to deal in 
 * the Software without restriction, including without limitation the rights to 
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
 * of the Software, and to permit persons to whom the Software is furnished to do so, 
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all 
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
 * SOFTWARE.
 */

using System;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using UnityEngine;

namespace Framework.Asynchronous
{
    public class CoroutineAwaiter : IAwaiter
    {
        protected readonly object Lock = new object();
        protected bool Done = false;
        protected Exception Exception;
        protected Action Continuation;

        public bool IsCompleted => this.Done;

        public void GetResult()
        {
            lock (Lock)
            {
                if (!Done)
                    throw new Exception("The task is not finished yet");
            }

            if (Exception != null)
                ExceptionDispatchInfo.Capture(Exception).Throw();
        }

        public void SetResult(Exception exception)
        {
            lock (Lock)
            {
                if (Done)
                    return;

                this.Exception = exception;
                this.Done = true;
                try
                {
                    Continuation?.Invoke();
                }
                catch (Exception)
                {
                }
                finally
                {
                    this.Continuation = null;
                }
            }
        }

        public void OnCompleted(Action continuation)
        {
            ((ICriticalNotifyCompletion) this).UnsafeOnCompleted(continuation);
        }

        void ICriticalNotifyCompletion.UnsafeOnCompleted(Action continuation)
        {
            if (continuation == null)
                throw new ArgumentNullException(nameof(continuation));

            lock (Lock)
            {
                if (this.Done)
                {
                    continuation();
                }
                else
                {
                    this.Continuation += continuation;
                }
            }
        }
    }

    public class CoroutineAwaiter<T> : CoroutineAwaiter, IAwaiter<T>
    {
        protected T Result;

        public CoroutineAwaiter()
        {
        }

        public new T GetResult()
        {
            lock (Lock)
            {
                if (!Done)
                    throw new Exception("The task is not finished yet");
            }

            if (Exception != null)
                ExceptionDispatchInfo.Capture(Exception).Throw();

            return Result;
        }

        public void SetResult(T result, Exception exception)
        {
            lock (Lock)
            {
                if (Done)
                    return;

                this.Result = result;
                this.Exception = exception;
                this.Done = true;
                try
                {
                    Continuation?.Invoke();
                }
                catch (Exception)
                {
                }
                finally
                {
                    this.Continuation = null;
                }
            }
        }
    }

    public struct AsyncOperationAwaiter : IAwaiter
    {
        private readonly AsyncOperation _asyncOperation;
        private Action<AsyncOperation> _continuationAction;

        public AsyncOperationAwaiter(AsyncOperation asyncOperation)
        {
            this._asyncOperation = asyncOperation;
            this._continuationAction = null;
        }

        public bool IsCompleted => _asyncOperation.isDone;

        public void GetResult()
        {
            if (!IsCompleted)
                throw new Exception("The task is not finished yet");

            if (_continuationAction != null)
                _asyncOperation.completed -= _continuationAction;
            _continuationAction = null;
        }

        public void OnCompleted(Action continuation)
        {
            ((ICriticalNotifyCompletion) this).UnsafeOnCompleted(continuation);
        }

        void ICriticalNotifyCompletion.UnsafeOnCompleted(Action continuation)
        {
            if (continuation == null)
                throw new ArgumentNullException(nameof(continuation));

            if (_asyncOperation.isDone)
            {
                continuation();
            }
            else
            {
                _continuationAction = (ao) => { continuation(); };
                _asyncOperation.completed += _continuationAction;
            }
        }
    }

    public struct AsyncOperationAwaiter<T, TResult> : IAwaiter<TResult>
        where T : AsyncOperation
    {
        private readonly T _asyncOperation;
        private readonly Func<T, TResult> _getter;
        private Action<AsyncOperation> _continuationAction;

        public AsyncOperationAwaiter(T asyncOperation, Func<T, TResult> getter)
        {
            this._asyncOperation = asyncOperation ?? throw new ArgumentNullException(nameof(asyncOperation));
            this._getter = getter ?? throw new ArgumentNullException(nameof(getter));
            this._continuationAction = null;
        }

        public bool IsCompleted => _asyncOperation.isDone;

        public TResult GetResult()
        {
            if (!IsCompleted)
                throw new Exception("The task is not finished yet");

            if (_continuationAction != null)
            {
                _asyncOperation.completed -= _continuationAction;
                _continuationAction = null;
            }

            return _getter(_asyncOperation);
        }

        public void OnCompleted(Action continuation)
        {
            ((ICriticalNotifyCompletion) this).UnsafeOnCompleted(continuation);
        }

        void ICriticalNotifyCompletion.UnsafeOnCompleted(Action continuation)
        {
            if (continuation == null)
                throw new ArgumentNullException(nameof(continuation));

            if (_asyncOperation.isDone)
            {
                continuation();
            }
            else
            {
                _continuationAction = (ao) => { continuation(); };
                _asyncOperation.completed += _continuationAction;
            }
        }
    }

    public struct AsyncResultAwaiter<T> : IAwaiter where T : IAsyncResult
    {
        private T _asyncResult;

        public AsyncResultAwaiter(T asyncResult)
        {
            if (asyncResult == null)
                throw new ArgumentNullException(nameof(asyncResult));
            this._asyncResult = asyncResult;
        }

        public bool IsCompleted => _asyncResult.IsDone;

        public void GetResult()
        {
            if (!IsCompleted)
                throw new Exception("The task is not finished yet");

            if (_asyncResult.Exception != null)
                ExceptionDispatchInfo.Capture(_asyncResult.Exception).Throw();
        }

        public void OnCompleted(Action continuation)
        {
            ((ICriticalNotifyCompletion) this).UnsafeOnCompleted(continuation);
        }

        void ICriticalNotifyCompletion.UnsafeOnCompleted(Action continuation)
        {
            if (continuation == null)
                throw new ArgumentNullException(nameof(continuation));
            _asyncResult.Callbackable().OnCallback((ar) => { continuation(); });
        }
    }

    public struct AsyncResultAwaiter<T, TResult> : IAwaiter<TResult>
        where T : IAsyncResult<TResult>
    {
        private T _asyncResult;

        public AsyncResultAwaiter(T asyncResult)
        {
            if (asyncResult == null)
                throw new ArgumentNullException(nameof(asyncResult));
            this._asyncResult = asyncResult;
        }

        public bool IsCompleted => _asyncResult.IsDone;

        public TResult GetResult()
        {
            if (!IsCompleted)
                throw new Exception("The task is not finished yet");

            if (_asyncResult.Exception != null)
                ExceptionDispatchInfo.Capture(_asyncResult.Exception).Throw();

            return this._asyncResult.Result;
        }

        public void OnCompleted(Action continuation)
        {
            ((ICriticalNotifyCompletion) this).UnsafeOnCompleted(continuation);
        }

        void ICriticalNotifyCompletion.UnsafeOnCompleted(Action continuation)
        {
            if (continuation == null)
                throw new ArgumentNullException(nameof(continuation));
            _asyncResult.Callbackable().OnCallback((ar) => { continuation(); });
        }
    }
}

<|start_filename|>Editor/BuildConfig/CompileCallback.cs<|end_filename|>
﻿namespace Framework.Editor
{
    public static class CompileCallback
    {
        [UnityEditor.Callbacks.DidReloadScripts]
        private static void OnScriptCompile()
        {
            ILRuntimeAutoCompile();
        }

        private static void ILRuntimeAutoCompile()
        {
#if ILRUNTIME
            var config = ConfigBase.Load<FrameworkRuntimeConfig>().ILRConfig;
            if(!config.UseHotFix || !config.AutoCompile) return;
            ILRuntimeBuildDll.DebugBuild();
#endif
        }   
    }
}

<|start_filename|>Runtime/UI/Core/Bind/IBindMulView.cs<|end_filename|>
namespace Framework.UI.Core.Bind
{
    /// <summary>
    /// 为了实现一个list vm绑定多个不同的view
    /// 可以用在聊天列表，同一个list用在两个不同的view上
    /// </summary>
    public interface IBindMulView
    {
        int Tag { get; set; }
    }
}

<|start_filename|>Runtime/Tool/ReflectionHelper.cs<|end_filename|>
﻿using System;
using System.Collections.Generic;
using System.Reflection;
using Framework;
using Framework.UI.Core;
#if ILRUNTIME
using ILRuntime.CLR.TypeSystem;
using ILRuntime.Reflection;
using ILRuntime.Runtime.Enviorment;
using ILRuntime.Runtime.Intepreter;
#endif

namespace Tool
{
    public static class ReflectionHelper
    {
        private static readonly bool useHotfix;
        /// <summary>
        /// 不使用ilruntime时，game@hotfix.asmdef的程序集
        /// </summary>
        private static Assembly curHotfixAssembly;
        private static Assembly curGameAssembly;
        private const string IlRuntimeDllName = "ILRuntime";

        static ReflectionHelper()
        {
            var runtimeConfig = ConfigBase.Load<FrameworkRuntimeConfig>();
#if ILRUNTIME
            useHotfix = runtimeConfig.ILRConfig.UseHotFix;
            curHotfixAssembly = AssemblyManager.GetAssembly(runtimeConfig.ILRConfig.DllName);
#endif
            curGameAssembly = AssemblyManager.GetAssembly(runtimeConfig.GameDllName);
        }
        
        public static T CreateInstance<T>(params object[] args)
        {
            var type = typeof(T).GetCLRType();
            T result;
#if ILRUNTIME
            if (type.Assembly.GetName().Name == IlRuntimeDllName)
            {
                result = ILRuntimeHelper.Appdomain.Instantiate<T>(type.FullName, args);
            }
            else
#endif
            {
                result = (T)Activator.CreateInstance(type, args);
            }
            return result;
        }

        public static object CreateInstance(Type type, params object[] args)
        {
            object result;
#if ILRUNTIME
            if (type.Assembly.GetName().Name == IlRuntimeDllName)
            {
                ILTypeInstance ins = ILRuntimeHelper.Appdomain.Instantiate(type.FullName, args);
                return ins.CLRInstance;
            }
#endif
            result = Activator.CreateInstance(type, args);
            return result;
        }

        public static object CreateInstance(string type, params object[] args)
        {
            return CreateInstance(GetType(type), args);
        }

        public static Type GetCLRType(this object obj)
        {
#if ILRUNTIME
            //如果是继承了主项目的热更的类型
            if (obj is CrossBindingAdaptorType adaptor)
            {
                return adaptor.ILInstance.Type.ReflectionType;
            }
            //如果是热更的类型
            if (obj is ILTypeInstance ilInstance)
            {
                return ilInstance.Type.ReflectionType;
            }
#endif
            return obj.GetType();
        }

        public static Type GetCLRType(this Type type)
        {
            return GetCLRTypeFunc(type);
        }
        
        public static Type GetCLRTypeFunc(Type type)
        {
#if ILRUNTIME
            if (type is ILRuntimeType runtimeType)
                return runtimeType.ILType.ReflectionType;
            if (type is ILRuntimeWrapperType wrapperType)
                return wrapperType.RealType;
#endif
            return type;
        }

#if ILRUNTIME
        public static Type GetCLRType(this IType type)
        {
            if (type is CLRType clrType)
            {
                return clrType.TypeForCLR;
            }
            return type.ReflectionType;
        }
#endif
        
        public static Type GetType(string type)
        {
            Type result = null;
#if ILRUNTIME
            result = useHotfix ? ILRuntimeHelper.GetType(type) : curHotfixAssembly.GetType(type);
#endif
            if (result == null)
            {
                result = curGameAssembly.GetType(type);
            }
            return result;
        }
    }
}

<|start_filename|>Runtime/UI/Wrap/Base/IFieldChangeCb.cs<|end_filename|>
﻿using System;

namespace Framework.UI.Wrap.Base
{
    public interface IFieldChangeCb<T>
    {
        Action<T> GetFieldChangeCb();
    }
}

<|start_filename|>Tests/Editor/UI.cs<|end_filename|>
﻿using System;
using Framework.UI.Core;
using Framework.UI.Core.Bind;
using Framework.UI.Wrap.Base;
using NSubstitute;
using NUnit.Framework;
using UnityEngine.Events;
using UnityEngine.UI;

namespace Tests
{
    public class TestView : IComponentEvent, IFieldChangeCb<string>, IComponentEvent<int>, IFieldChangeCb<int>
    {
        private UnityEvent TestEvent = new UnityEvent();
        private UnityEvent<int> EventWithPara = new Dropdown.DropdownEvent();

        UnityEvent IComponentEvent.GetComponentEvent()
        {
            return TestEvent;
        }

        public string Name;
        public int Age;

        public Action<string> GetFieldChangeCb()
        {
            return (value) => Name = value;
        }

        UnityEvent<int> IComponentEvent<int>.GetComponentEvent()
        {
            return EventWithPara;
        }

        Action<int> IFieldChangeCb<int>.GetFieldChangeCb()
        {
            return value => Age = value;
        }
    }

    public interface BindCommand
    {
        void Func();
        void FuncWithPara();
    }

    public class UI测试
    {
        [Test]
        public void BindCommand()
        {
            IComponentEvent view = new TestView();
            bool isTrigger = false;
            BindFactory factory = new BindFactory(view);

            void Func()
            {
                isTrigger = !isTrigger;
            }

            factory.BindCommand(view, Func);
            factory.Reset();
            view.GetComponentEvent().Invoke();
            Assert.IsTrue(isTrigger);
        }

        [Test]
        public void Bind带参Command()
        {
            IComponentEvent<int> view = new TestView();
            int result = -1;
            BindFactory factory = new BindFactory(view);

            void Func(int a)
            {
                result = a;
            }

            factory.BindCommand<IComponentEvent<int>, int>(view, Func);
            view.GetComponentEvent().Invoke(2);
            Assert.IsTrue(result == 2);
        }

        [Test]
        public void BindProperty()
        {
            TestView view = new TestView();
            BindFactory factory = new BindFactory(view);
            ObservableProperty<string> property = Substitute.For<ObservableProperty<string>>("哈哈");
            factory.Bind(view, property);
            Assert.IsTrue(view.Name == "哈哈");
            property.Value = "修改";
            Assert.IsTrue(view.Name == "修改");
        }

        [Test]
        public void BindProperty不同类型wrap()
        {
            TestView view = new TestView();
            BindFactory factory = new BindFactory(view);
            ObservableProperty<int> property = Substitute.For<ObservableProperty<int>>(1);
            factory.Bind(view, property, (field) => field + "wrap");
            Assert.IsTrue(view.Name == "1wrap");
            property.Value = 2;
            Assert.IsTrue(view.Name == "2wrap");
        }

        [Test]
        public void BindProperty多个字段()
        {
            TestView view = new TestView();
            BindFactory factory = new BindFactory(view);
            ObservableProperty<string> property1 = Substitute.For<ObservableProperty<string>>("p1");
            ObservableProperty<string> property2 = Substitute.For<ObservableProperty<string>>("p2");
            //factory.Bind(view, property, (field) => field + "wrap");
            factory.Bind(view, property1, property2, (i1, i2) => i1 + i2);
            Assert.IsTrue(view.Name == "p1p2");
            property1.Value = "p3";
            Assert.IsTrue(view.Name == "p3p2");
            property2.Value = "p4";
            Assert.IsTrue(view.Name == "p3p4");
        }

        [Test]
        public void BindProperty多个字段wrap()
        {
            TestView view = new TestView();
            BindFactory factory = new BindFactory(view);
            ObservableProperty<int> property1 = Substitute.For<ObservableProperty<int>>(1);
            ObservableProperty<int> property2 = Substitute.For<ObservableProperty<int>>(2);
            //factory.Bind(view, property, (field) => field + "wrap");
            factory.Bind(view, property1, property2, (i1, i2) => (i1 + i2) + "wrap");
            Assert.IsTrue(view.Name == "3wrap");
            property1.Value = 2;
            Assert.IsTrue(view.Name == "4wrap");
            property2.Value = 3;
            Assert.IsTrue(view.Name == "5wrap");
        }

        [Test]
        public void 反向绑定()
        {
            TestView view = new TestView();
            BindFactory factory = new BindFactory(view);
            ObservableProperty<int> property = Substitute.For<ObservableProperty<int>>(1);
            factory.RevertBind(view, property);
            ((IComponentEvent<int>) view).GetComponentEvent().Invoke(2);
            Assert.IsTrue(property.Value == 2);
        }

        [Test]
        public void 双向绑定()
        {
            TestView view = new TestView();
            BindFactory factory = new BindFactory(view);
            ObservableProperty<int> property = Substitute.For<ObservableProperty<int>>(1);
            factory.TwoWayBind(view, property);
            Assert.IsTrue(view.Age == 1);
            property.Value = 2;
            Assert.IsTrue(view.Age == 2);
            ((IComponentEvent<int>) view).GetComponentEvent().Invoke(3);
            Assert.IsTrue(property.Value == 3);
        }

        [Test]
        public void 不同双向绑定()
        {
            TestView view = new TestView();
            BindFactory factory = new BindFactory(view);
            ObservableProperty<string> property = Substitute.For<ObservableProperty<string>>("1");
            factory.TwoWayBind<TestView, string, int>(view, property, (i) => i.ToString(), int.Parse);
            Assert.IsTrue(view.Age == 1);
            property.Value = "2";
            Assert.IsTrue(view.Age == 2);
            ((IComponentEvent<int>) view).GetComponentEvent().Invoke(3);
            Assert.IsTrue(property.Value == "3");
        }
    }
}

<|start_filename|>Runtime/Tool/FileHelper.cs<|end_filename|>
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace Framework.Helper
{
    public static class FileHelper
    {
        public static void DeepSearchDirFiles(string dirPath, Action<FileInfo> action, string pattern = "*")
        {
            DirectoryInfo dir = new DirectoryInfo(dirPath);
            if(!dir.Exists) return;
            foreach (var fileInfo in dir.GetFiles(pattern))
            {
                action?.Invoke(fileInfo);
            }
            foreach (var directoryInfo in dir.GetDirectories())
            {
                DeepSearchDirFiles(directoryInfo.FullName, action);
            }
        }
        
        public static void DeepSearchDirFiles(string dirPath, ref List<string> fileNames, string pattern = "*")
        {
            fileNames.AddRange(Directory.GetFiles(dirPath, pattern, SearchOption.TopDirectoryOnly));
            foreach (var directory in Directory.GetDirectories(dirPath))
            {
                DeepSearchDirFiles(directory, ref fileNames, pattern);
            }
        }

        public static void CopyFileStreaming(string from, string to)
        {
            byte[] buffer = new byte[32 * 1024];
            using (FileStream fromFile = new FileStream(from, FileMode.Open, FileAccess.Read))
            {
                using (FileStream toFile =
                    new FileStream(to, FileMode.OpenOrCreate, FileAccess.Write))
                {
                    int bytesRead;
                    while ((bytesRead = fromFile.Read(buffer, 0, buffer.Length)) != 0)
                    {
                        toFile.Write(buffer, 0, bytesRead);
                    }
                }
            }
        }
        
        public static string GetRelativePath(string currentPath, string fromDirectory)
        {
            if (fromDirectory == null)
                throw new ArgumentNullException(nameof(fromDirectory));

            if (currentPath == null)
                throw new ArgumentNullException(nameof(currentPath));

            if (!currentPath.Contains(fromDirectory))
                throw new Exception($"路径出错 {currentPath}   {fromDirectory}");

            var result = currentPath.RemoveString(fromDirectory);
            if (result.StartsWith("/") || result.StartsWith("\\"))
            {
                result = result.Remove(0,1);
            }
            return result;
        }
    }
}

<|start_filename|>Runtime/Asynchronous/IPromise.cs<|end_filename|>
﻿/*
 * MIT License
 *
 * Copyright (c) 2018 <NAME>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of 
 * this software and associated documentation files (the "Software"), to deal in 
 * the Software without restriction, including without limitation the rights to 
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
 * of the Software, and to permit persons to whom the Software is furnished to do so, 
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all 
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
 * SOFTWARE.
 */

using System;

namespace Framework.Asynchronous
{
    /// <summary>
    /// 
    /// </summary>
    public interface IPromise
    {
        /// <summary>
        /// The execution result
        /// </summary>
        object Result { get; }

        /// <summary>
        /// Exception
        /// </summary>
        Exception Exception { get; }

        /// <summary>
        /// Returns  "true" if this task finished.
        /// </summary>
        bool IsDone { get; }

        /// <summary>
        /// Returns "true" if this task was cancelled before it completed normally.
        /// </summary>
        bool IsCancelled { get; }

        /// <summary>
        /// Returns  "true" if there is a cancellation request.
        /// </summary>
        bool IsCancellationRequested { get; }

        /// <summary>
        /// 
        /// </summary>
        void SetCancelled();

        /// <summary>
        /// 
        /// </summary>
        /// <param name="error"></param>
        void SetException(string error);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="exception"></param>
        void SetException(Exception exception);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="result"></param>
        void SetResult(object result = null);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="TResult"></typeparam>
    public interface IPromise<TResult> : IPromise
    {
        /// <summary>
        /// The execution result
        /// </summary>
        new TResult Result { get; }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="result"></param>
        void SetResult(TResult result);
    }
}


<|start_filename|>Runtime/Domain/DomainAttribute.cs<|end_filename|>
namespace Framework
{
    public class DomainAttribute : ManagerAttribute
    {
        public DomainAttribute(int intTag) : base(intTag)
        {
        }
    }
}

<|start_filename|>Tests/Editor/Message.cs<|end_filename|>
﻿using System.Collections.Generic;
using Framework.MessageCenter;
using NSubstitute;
using NUnit.Framework;

namespace Tests
{
    public class 消息系统
    {

        private const string IntTag = "IntTag";
        private const string IntTag2 = "IntTag2";
        private const string TriggerTag = "TAG2";
        private const string ObjTag = "TAG3";

        public interface Receive
        {
            [Subscriber(IntTag, IntTag2)]
            void ReceiveInt(int val);

            [Subscriber(TriggerTag)]
            void ReceiveTrigger();

            [Subscriber(ObjTag)]
            void ReceiveObj(Receive obj);
        }

        [Test]
        public void 注册和广播()
        {
            var receive = Substitute.For<Receive>();
            Message.defaultEvent.Register(receive);
            Message.defaultEvent.Post(IntTag, 1);
            receive.Received().ReceiveInt(1);
            Message.defaultEvent.Post(IntTag2, 2);
            receive.Received().ReceiveInt(2);
            Message.defaultEvent.Post(TriggerTag);
            receive.Received().ReceiveTrigger();
            Message.defaultEvent.Post(ObjTag, receive);
            receive.Received().ReceiveObj(receive);
        }
    }
}

<|start_filename|>Runtime/Common/ScriptCollection/FilterEnumerator.cs<|end_filename|>
﻿using System;
using System.Collections;
using System.Collections.Generic;

namespace Framework.Helper
{
    public class FilterEnumerator : IEnumerator
    {
        private readonly IEnumerator _enumerator;
        private readonly Predicate<object> _match;

        public FilterEnumerator(IEnumerator enumerator, Predicate<object> match)
        {
            _enumerator = enumerator;
            _match = match;
        }

        public object Current { get; private set; }

        public bool MoveNext()
        {
            while (_enumerator.MoveNext())
            {
                var current = _enumerator.Current;
                if (!_match(current))
                    continue;

                Current = current;
                return true;
            }

            return false;
        }
        
        public IEnumerator GetEnumerator()
        {
            return this;
        }

        public void Reset()
        {
            _enumerator.Reset();
        }
    }

    public class FilterEnumerator<T> : IEnumerator<T>
    {
        private IEnumerator<T> _enumerator;
        private Predicate<T> _match;

        public FilterEnumerator(IEnumerator<T> enumerator, Predicate<T> match)
        {
            Current = default;
            _enumerator = enumerator;
            _match = match;
        }

        public T Current { get; private set; }

        object IEnumerator.Current => Current;

        public bool MoveNext()
        {
            while (_enumerator.MoveNext())
            {
                var current = _enumerator.Current;
                if (!_match(current))
                    continue;

                Current = current;
                return true;
            }

            return false;
        }
        
        public IEnumerator<T> GetEnumerator()
        {
            return this;
        }

        public void Reset()
        {
            _enumerator.Reset();
        }

        #region IDisposable Support

        private bool _disposedValue;

        protected virtual void Dispose(bool disposing)
        {
            if (!_disposedValue)
            {
                Reset();
                _enumerator = null;
                _match = null;
                _disposedValue = true;
            }
        }

        ~FilterEnumerator()
        {
            Dispose(false);
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        #endregion
    }
}


<|start_filename|>Runtime/Tool/Net/Http/DownloadFileHandler.cs<|end_filename|>
﻿/*
 * MIT License
 *
 * Copyright (c) 2018 <NAME>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of 
 * this software and associated documentation files (the "Software"), to deal in 
 * the Software without restriction, including without limitation the rights to 
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
 * of the Software, and to permit persons to whom the Software is furnished to do so, 
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all 
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
 * SOFTWARE.
 #1#
*/
using System.IO;
using System.Threading;
using UnityEngine;
using UnityEngine.Networking;

namespace Framework.Net
{
    public class DownloadFileHandler : DownloadHandlerScript
    {
        private int _totalSize = -1;
        private int _completedSize = 0;
        private readonly FileInfo _fileInfo;
        private readonly FileInfo _tmpFileInfo;
        private FileStream _fileStream;
        public bool WriteFinish { get; private set; }

        public DownloadFileHandler(string fileName) : this(new FileInfo(fileName))
        {
        }

        public DownloadFileHandler(FileInfo fileInfo) : base(new byte[8192])
        {
            this._fileInfo = fileInfo;
            this._tmpFileInfo = new FileInfo(this._fileInfo.FullName + ".tmp");
            if (this._tmpFileInfo.Exists)
                _tmpFileInfo.Delete();

            if (_tmpFileInfo.Directory != null && !_tmpFileInfo.Directory.Exists)
                _tmpFileInfo.Directory.Create();

            this._fileStream = _tmpFileInfo.Create();
        }

        protected override byte[] GetData()
        {
            return null;
        }

        protected override bool ReceiveData(byte[] data, int dataLength)
        {
            if (data == null || data.Length < 1)
                return false;

            _fileStream.Write(data, 0, dataLength);
            _fileStream.Flush();
            _completedSize += dataLength;
            return true;
        }

        protected override float GetProgress()
        {
            if (_totalSize <= 0)
                return 0;
            return (float) _completedSize / _totalSize;
        }

        protected override void CompleteContent()
        {
            ThreadPool.QueueUserWorkItem((obj) =>
            {
                if (_fileStream != null)
                {
                    _fileStream.Dispose();
                    _fileStream = null;
                }

                if (_fileInfo.Exists)
                    _fileInfo.Delete();

                _tmpFileInfo.MoveTo(_fileInfo.FullName);
                WriteFinish = true;
            });
        }

        protected override void ReceiveContentLengthHeader(ulong contentLength)
        {
            this._totalSize = (int) contentLength;
        }

        ~DownloadFileHandler()
        {
            if (_fileStream == null) return;
            _fileStream.Dispose();
            _fileStream = null;
        }
    }
}



<|start_filename|>Runtime/Asynchronous/IAsyncTask.cs<|end_filename|>
﻿/*
 * MIT License
 *
 * Copyright (c) 2018 <NAME>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of 
 * this software and associated documentation files (the "Software"), to deal in 
 * the Software without restriction, including without limitation the rights to 
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
 * of the Software, and to permit persons to whom the Software is furnished to do so, 
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all 
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
 * SOFTWARE.
 */

using System;

namespace Framework.Asynchronous
{
    /// <summary>
    /// 
    /// </summary>
    public interface IAsyncTask : IAsyncResult
    {
        /// <summary>
        /// Triggered when a task starts.
        /// </summary>
        /// <param name="callback"></param>
        /// <param name="runOnMainThread"></param>
        /// <returns></returns>
        IAsyncTask OnPreExecute(Action callback, bool runOnMainThread = true);

        /// <summary>
        /// Triggered when the task is completed.
        /// </summary>
        /// <param name="callback"></param>
        /// <param name="runOnMainThread"></param>
        /// <returns></returns>
        IAsyncTask OnPostExecute(Action callback, bool runOnMainThread = true);

        /// <summary>
        /// Triggered when an error occurs.
        /// </summary>
        /// <param name="callback"></param>
        /// <param name="runOnMainThread"></param>
        /// <returns></returns>
        IAsyncTask OnError(Action<Exception> callback, bool runOnMainThread = true);

        /// <summary>
        /// Always call the end of the task.
        /// </summary>
        /// <param name="callback"></param>
        /// <param name="runOnMainThread"></param>
        /// <returns></returns>
        IAsyncTask OnFinish(Action callback, bool runOnMainThread = true);

        /// <summary>
        /// Start the task after the given delay.
        /// </summary>
        /// <param name="delay">millisecond</param>
        /// <returns></returns>
        IAsyncTask Start(int delay);

        /// <summary>
        /// Start the task.
        /// </summary>
        /// <returns></returns>
        IAsyncTask Start();
    }

    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="TResult"></typeparam>
    public interface IAsyncTask<TResult> : IAsyncResult<TResult>
    {
        /// <summary>
        /// Triggered when a task starts.
        /// </summary>
        /// <param name="callback"></param>
        /// <param name="runOnMainThread"></param>
        /// <returns></returns>
        IAsyncTask<TResult> OnPreExecute(Action callback, bool runOnMainThread = true);

        /// <summary>
        /// Triggered when the task is completed.
        /// </summary>
        /// <param name="callback"></param>
        /// <param name="runOnMainThread"></param>
        /// <returns></returns>
        IAsyncTask<TResult> OnPostExecute(Action<TResult> callback, bool runOnMainThread = true);

        /// <summary>
        /// Triggered when an error occurs.
        /// </summary>
        /// <param name="callback"></param>
        /// <param name="runOnMainThread"></param>
        /// <returns></returns>
        IAsyncTask<TResult> OnError(Action<Exception> callback, bool runOnMainThread = true);

        /// <summary>
        /// Always call the end of the task.
        /// </summary>
        /// <param name="callback"></param>
        /// <param name="runOnMainThread"></param>
        /// <returns></returns>
        IAsyncTask<TResult> OnFinish(Action callback, bool runOnMainThread = true);

        /// <summary>
        /// Start the task after the given delay.
        /// </summary>
        /// <param name="delay">millisecond</param>
        /// <returns></returns>
        IAsyncTask<TResult> Start(int delay);

        /// <summary>
        /// Start the task.
        /// </summary>
        /// <returns></returns>
        IAsyncTask<TResult> Start();
    }

}


<|start_filename|>Editor/UI/ScrollView/LoopScrollRectInspector.cs<|end_filename|>
﻿using Framework.UI;
using UnityEngine;
using UnityEditor;

namespace Framework.Editor.UI
{
	[CustomEditor(typeof(LoopScrollRect), true)]
	public class LoopScrollRectInspector : UnityEditor.Editor
	{
		int index = 0;
		float speed = 1000;

		public override void OnInspectorGUI()
		{
			base.OnInspectorGUI();
			EditorGUILayout.Space();

			LoopScrollRect scroll = (LoopScrollRect) target;
			GUI.enabled = Application.isPlaying;

			EditorGUILayout.BeginHorizontal();
			if (GUILayout.Button("Clear"))
			{
				scroll.ClearCells();
			}

			if (GUILayout.Button("Refresh"))
			{
				scroll.RefreshCells();
			}

			if (GUILayout.Button("Refill"))
			{
				scroll.RefillCells();
			}

			if (GUILayout.Button("RefillFromEnd"))
			{
				scroll.RefillCellsFromEnd();
			}

			EditorGUILayout.EndHorizontal();

			EditorGUIUtility.labelWidth = 45;
			float w = (EditorGUIUtility.currentViewWidth - 100) / 2;
			EditorGUILayout.BeginHorizontal();
			index = EditorGUILayout.IntField("Index", index, GUILayout.Width(w));
			speed = EditorGUILayout.FloatField("Speed", speed, GUILayout.Width(w));
			if (GUILayout.Button("Scroll", GUILayout.Width(45)))
			{
				scroll.SrollToCell(index, speed);
			}

			EditorGUILayout.EndHorizontal();
		}
	}
}

<|start_filename|>Runtime/Execution/InterceptableEnumerator.cs<|end_filename|>
﻿/*
 * MIT License
 *
 * Copyright (c) 2018 <NAME>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of 
 * this software and associated documentation files (the "Software"), to deal in 
 * the Software without restriction, including without limitation the rights to 
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
 * of the Software, and to permit persons to whom the Software is furnished to do so, 
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all 
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
 * SOFTWARE.
 */

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Framework.Execution
{
    /// <summary>
    /// Interceptable enumerator
    /// </summary>
    public class InterceptableEnumerator : IEnumerator
    {
        private object _current;
        private readonly Stack<IEnumerator> _stack = new Stack<IEnumerator>();

        private Action<Exception> _onException;
        private Action _onFinally;
        private Func<bool> _hasNext;

        public InterceptableEnumerator(IEnumerator routine)
        {
            this._stack.Push(routine);
        }

        public object Current => this._current;

        public bool MoveNext()
        {
            try
            {
                if (!this.HasNext())
                {
                    this.OnFinally();
                    return false;
                }

                if (_stack.Count <= 0)
                {
                    this.OnFinally();
                    return false;
                }

                IEnumerator ie = _stack.Peek();
                bool hasNext = ie.MoveNext();
                if (!hasNext)
                {
                    this._stack.Pop();
                    return MoveNext();
                }

                this._current = ie.Current;
                if (this._current is IEnumerator current)
                {
                    _stack.Push(current);
                    return MoveNext();
                }

                if (this._current is Coroutine)
                    Log.Warning(
                        "The Enumerator's results contains the 'UnityEngine.Coroutine' type,If occurs an exception,it can't be catched.It is recommended to use 'yield return routine',rather than 'yield return StartCoroutine(routine)'.");

                return true;
            }
            catch (Exception e)
            {
                this.OnException(e);
                this.OnFinally();
                return false;
            }
        }

        public void Reset()
        {
            throw new NotSupportedException();
        }

        private void OnException(Exception e)
        {
            try
            {
                if (this._onException == null)
                    return;

                foreach (var @delegate in this._onException.GetInvocationList())
                {
                    var action = (Action<Exception>) @delegate;
                    try
                    {
                        action(e);
                    }
                    catch (Exception ex)
                    {
                        Log.Warning(ex);
                    }
                }
            }
            catch (Exception)
            {
            }
        }

        private void OnFinally()
        {
            try
            {
                if (this._onFinally == null)
                    return;

                foreach (var @delegate in this._onFinally.GetInvocationList())
                {
                    var action = (Action) @delegate;
                    try
                    {
                        action();
                    }
                    catch (Exception ex)
                    {
                        Log.Warning(ex);
                    }
                }
            }
            catch (Exception)
            {
            }
        }

        private bool HasNext()
        {
            return _hasNext == null || _hasNext();
        }

        /// <summary>
        /// Register a condition code block.
        /// </summary>
        /// <param name="hasNext"></param>
        public virtual void RegisterConditionBlock(Func<bool> hasNext)
        {
            this._hasNext = hasNext;
        }

        /// <summary>
        /// Register a code block, when an exception occurs it will be executed.
        /// </summary>
        /// <param name="onException"></param>
        public virtual void RegisterCatchBlock(Action<Exception> onException)
        {
            this._onException += onException;
        }

        /// <summary>
        /// Register a code block, when the end of the operation is executed.
        /// </summary>
        /// <param name="onFinally"></param>
        public virtual void RegisterFinallyBlock(Action onFinally)
        {
            this._onFinally += onFinally;
        }
    }
}


<|start_filename|>Runtime/Common/ScriptCollection/ConvertEnumerator.cs<|end_filename|>
﻿using System;
using System.Collections;
using System.Collections.Generic;

namespace Framework.Helper
{
    public class ConvertEnumerator : IEnumerator
    {
        private readonly IEnumerator _enumerator;
        private readonly Converter<object, object> _converter;

        public ConvertEnumerator(IEnumerator enumerator, Converter<object, object> converter)
        {
            _enumerator = enumerator;
            _converter = converter;
        }

        public object Current { get; private set; }

        public bool MoveNext()
        {
            if (_enumerator.MoveNext())
            {
                var current = _enumerator.Current;
                Current = _converter(current);
                return true;
            }

            return false;
        }
        
        public IEnumerator GetEnumerator()
        {
            return this;
        }

        public void Reset()
        {
            _enumerator.Reset();
        }
    }

    public class ConvertEnumerator<TInput, TOutput> : IEnumerator<TOutput>
    {
        private IEnumerator<TInput> _enumerator;
        private Converter<TInput, TOutput> _converter;

        public ConvertEnumerator(IEnumerator<TInput> enumerator, Converter<TInput, TOutput> converter)
        {
            _enumerator = enumerator;
            _converter = converter;
        }

        public TOutput Current { get; private set; }

        object IEnumerator.Current => Current;

        public bool MoveNext()
        {
            if (_enumerator.MoveNext())
            {
                var current = _enumerator.Current;
                Current = _converter(current);
                return true;
            }

            return false;
        }

        public IEnumerator<TOutput> GetEnumerator()
        {
            return this;
        }
        
        public void Reset()
        {
            _enumerator.Reset();
        }

        #region IDisposable Support

        private bool _disposedValue;

        protected virtual void Dispose(bool disposing)
        {
            if (!_disposedValue)
            {
                Reset();
                _enumerator = null;
                _converter = null;
                _disposedValue = true;
            }
        }

        ~ConvertEnumerator()
        {
            Dispose(false);
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        #endregion
    }
}

<|start_filename|>Runtime/Domain/DomainManager.cs<|end_filename|>
using System;
using System.Collections.Generic;

namespace Framework
{
    public class DomainManager : ManagerBase<DomainManager, DomainAttribute, int>
    {
        Dictionary<int, IDomain> _allDomains = new Dictionary<int, IDomain>();
        public IDomain CurrentDomain { get; private set; }

        public override void Init()
        {
            foreach (var classData in this.GetAllClassDatas())
            {
                var attr = classData.Attribute as DomainAttribute;

                var sv = CreateInstance<IDomain>(attr.IntTag);
                //设置name属性
                var t = sv.GetType();
                t.GetProperty(nameof(IDomain.Name))?.SetValue(sv, attr.IntTag, null);
                RegisterScreen(sv);
            }
        }
        
        private void RegisterScreen(IDomain domain)
        {
            _allDomains.Add(domain.Name, domain);
        }

        public IDomain GetDomain(int svName)
        {
            IDomain sv = null;
            foreach (var _sv in _allDomains.Values)
            {
                if (_sv.Name == svName)
                {
                    sv = _sv;
                    break;
                }
            }
            return sv;
        }

        public IDomain GetDomain(Enum name)
        {
            return GetDomain(name.GetHashCode());
        }

        public void BeginNavTo(Enum name, object data = null)
        {
            BeginNavTo(name.GetHashCode(), data);
        }

        public void BeginNavTo(int name, object data = null)
        {
            if (CurrentDomain != null && CurrentDomain.Name == name)
            {
                Log.Error("别闹，当前就是" + CurrentDomain.GetType().Name);
                return;
            }
            
            if (_allDomains.TryGetValue(name, out var domain))
            {
                domain.BeginEnter(data);
                CurrentDomain?.BeginExit();
                CurrentDomain = domain;
            }
        }
    }
}

<|start_filename|>Runtime/Asynchronous/Callbackable.cs<|end_filename|>
﻿/*
 * MIT License
 *
 * Copyright (c) 2018 <NAME>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of 
 * this software and associated documentation files (the "Software"), to deal in 
 * the Software without restriction, including without limitation the rights to 
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
 * of the Software, and to permit persons to whom the Software is furnished to do so, 
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all 
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
 * SOFTWARE.
 */

using System;

namespace Framework.Asynchronous
{
    public interface ICallbackable
    {
        /// <summary>
        /// Called when the task is finished.
        /// </summary>
        /// <param name="callback"></param>
        void OnCallback(Action<IAsyncResult> callback);
    }

    public interface ICallbackable<TResult>
    {
        /// <summary>
        /// Called when the task is finished.
        /// </summary>
        /// <param name="callback"></param>
        void OnCallback(Action<IAsyncResult<TResult>> callback);
    }

    public interface IProgressCallbackable<TProgress>
    {
        /// <summary>
        /// Called when the task is finished.
        /// </summary>
        /// <param name="callback"></param>
        void OnCallback(Action<IProgressResult<TProgress>> callback);

        /// <summary>
        /// Called when the progress update.
        /// </summary>
        /// <param name="callback"></param>
        void OnProgressCallback(Action<TProgress> callback);
    }

    public interface IProgressCallbackable<TProgress, TResult>
    {
        /// <summary>
        /// Called when the task is finished.
        /// </summary>
        /// <param name="callback"></param>
        void OnCallback(Action<IProgressResult<TProgress, TResult>> callback);

        /// <summary>
        /// Called when the progress update.
        /// </summary>
        /// <param name="callback"></param>
        void OnProgressCallback(Action<TProgress> callback);
    }

    internal class Callbackable : ICallbackable
    {

        private readonly IAsyncResult _result;
        private readonly object _lock = new object();
        private Action<IAsyncResult> _callback;

        public Callbackable(IAsyncResult result)
        {
            this._result = result;
        }

        public void RaiseOnCallback()
        {
            lock (_lock)
            {
                try
                {
                    if (this._callback == null)
                        return;

                    var list = this._callback.GetInvocationList();
                    this._callback = null;

                    foreach (var @delegate in list)
                    {
                        var action = (Action<IAsyncResult>) @delegate;
                        try
                        {
                            action(this._result);
                        }
                        catch (Exception e)
                        {
                            Log.Error($"Class[{GetType()}] callback exception.Error:{e}");
                        }
                    }
                }
                catch (Exception e)
                {
                    Log.Error($"Class[{GetType()}] callback exception.Error:{e}");
                }
            }
        }

        public void OnCallback(Action<IAsyncResult> callback)
        {
            lock (_lock)
            {
                if (callback == null)
                    return;

                if (this._result.IsDone)
                {
                    try
                    {
                        callback(this._result);
                    }
                    catch (Exception e)
                    {
                        Log.Error($"Class[{GetType()}] callback exception.Error:{e}");
                    }

                    return;
                }

                this._callback += callback;
            }
        }
    }

    internal class Callbackable<TResult> : ICallbackable<TResult>
    {

        private IAsyncResult<TResult> result;
        private readonly object _lock = new object();
        private Action<IAsyncResult<TResult>> callback;

        public Callbackable(IAsyncResult<TResult> result)
        {
            this.result = result;
        }

        public void RaiseOnCallback()
        {
            lock (_lock)
            {
                try
                {
                    if (this.callback == null)
                        return;

                    var list = this.callback.GetInvocationList();
                    this.callback = null;

                    foreach (var @delegate in list)
                    {
                        var action = (Action<IAsyncResult<TResult>>) @delegate;
                        try
                        {
                            action(this.result);
                        }
                        catch (Exception e)
                        {
                            Log.Error($"Class[{GetType()}] callback exception.Error:{e}");
                        }
                    }
                }
                catch (Exception e)
                {
                    Log.Error($"Class[{GetType()}] callback exception.Error:{e}");
                }
            }
        }

        public void OnCallback(Action<IAsyncResult<TResult>> callback)
        {
            lock (_lock)
            {
                if (callback == null)
                    return;

                if (this.result.IsDone)
                {
                    try
                    {
                        callback(this.result);
                    }
                    catch (Exception e)
                    {
                        Log.Error($"Class[{GetType()}] callback exception.Error:{e}");
                    }

                    return;
                }

                this.callback += callback;
            }
        }
    }

    internal class ProgressCallbackable<TProgress> : IProgressCallbackable<TProgress>
    {

        private readonly IProgressResult<TProgress> _result;
        private readonly object _lock = new object();
        private Action<IProgressResult<TProgress>> _callback;
        private Action<TProgress> _progressCallback;

        public ProgressCallbackable(IProgressResult<TProgress> result)
        {
            this._result = result;
        }

        public void RaiseOnCallback()
        {
            lock (_lock)
            {
                try
                {
                    if (this._callback == null)
                        return;

                    var list = this._callback.GetInvocationList();
                    this._callback = null;

                    foreach (var @delegate in list)
                    {
                        var action = (Action<IProgressResult<TProgress>>) @delegate;
                        try
                        {
                            action(this._result);
                        }
                        catch (Exception e)
                        {
                            Log.Error($"Class[{GetType()}] callback exception.Error:{e}");
                        }
                    }
                }
                catch (Exception e)
                {
                    Log.Error($"Class[{GetType()}] callback exception.Error:{e}");
                }
                finally
                {
                    this._progressCallback = null;
                }
            }
        }

        public void RaiseOnProgressCallback(TProgress progress)
        {
            lock (_lock)
            {
                try
                {
                    if (this._progressCallback == null)
                        return;

                    var list = this._progressCallback.GetInvocationList();
                    foreach (var @delegate in list)
                    {
                        var action = (Action<TProgress>) @delegate;
                        try
                        {
                            action(progress);
                        }
                        catch (Exception e)
                        {
                            Log.Error($"Class[{GetType()}] callback exception.Error:{e}");
                        }
                    }
                }
                catch (Exception e)
                {
                    Log.Error($"Class[{GetType()}] callback exception.Error:{e}");
                }
            }
        }

        public void OnCallback(Action<IProgressResult<TProgress>> callback)
        {
            lock (_lock)
            {
                if (callback == null)
                    return;

                if (this._result.IsDone)
                {
                    try
                    {
                        callback(this._result);
                    }
                    catch (Exception e)
                    {
                        Log.Error($"Class[{GetType()}] callback exception.Error:{e}");
                    }

                    return;
                }

                this._callback += callback;
            }
        }

        public void OnProgressCallback(Action<TProgress> callback)
        {
            lock (_lock)
            {
                if (callback == null)
                    return;

                if (this._result.IsDone)
                {
                    try
                    {
                        callback(this._result.Progress);
                    }
                    catch (Exception e)
                    {
                        Log.Error($"Class[{GetType()}] callback exception.Error:{e}");
                    }

                    return;
                }

                this._progressCallback += callback;
            }
        }
    }

    internal class ProgressCallbackable<TProgress, TResult> : IProgressCallbackable<TProgress, TResult>
    {

        private readonly IProgressResult<TProgress, TResult> _result;
        private readonly object _lock = new object();
        private Action<IProgressResult<TProgress, TResult>> _callback;
        private Action<TProgress> _progressCallback;

        public ProgressCallbackable(IProgressResult<TProgress, TResult> result)
        {
            this._result = result;
        }

        public void RaiseOnCallback()
        {
            lock (_lock)
            {
                try
                {
                    if (this._callback == null)
                        return;

                    var list = this._callback.GetInvocationList();
                    this._callback = null;

                    foreach (var @delegate in list)
                    {
                        var action = (Action<IProgressResult<TProgress, TResult>>) @delegate;
                        try
                        {
                            action(this._result);
                        }
                        catch (Exception e)
                        {
                            Log.Error($"Class[{GetType()}] callback exception.Error:{e}");
                            throw;
                        }
                    }
                }
                catch (Exception e)
                {
                    Log.Error($"Class[{GetType()}] callback exception.Error:{e}");
                    throw;
                }
                finally
                {
                    this._progressCallback = null;
                }
            }
        }

        public void RaiseOnProgressCallback(TProgress progress)
        {
            lock (_lock)
            {
                try
                {
                    if (this._progressCallback == null)
                        return;

                    var list = this._progressCallback.GetInvocationList();
                    foreach (var @delegate in list)
                    {
                        var action = (Action<TProgress>) @delegate;
                        try
                        {
                            action(progress);
                        }
                        catch (Exception e)
                        {
                            Log.Error($"Class[{GetType()}] callback exception.Error:{e}");
                        }
                    }
                }
                catch (Exception e)
                {
                    Log.Error($"Class[{GetType()}] callback exception.Error:{e}");
                }
            }
        }

        public void OnCallback(Action<IProgressResult<TProgress, TResult>> callback)
        {
            lock (_lock)
            {
                if (callback == null)
                    return;

                if (this._result.IsDone)
                {
                    try
                    {
                        callback(this._result);
                    }
                    catch (Exception e)
                    {
                        Log.Error($"Class[{GetType()}] callback exception.Error:{e}");
                    }

                    return;
                }

                this._callback += callback;
            }
        }

        public void OnProgressCallback(Action<TProgress> callback)
        {
            lock (_lock)
            {
                if (callback == null)
                    return;

                if (this._result.IsDone)
                {
                    try
                    {
                        callback(this._result.Progress);
                    }
                    catch (Exception e)
                    {
                        Log.Error($"Class[{GetType()}] callback exception.Error:{e}");
                    }

                    return;
                }

                this._progressCallback += callback;
            }
        }
    }
}

<|start_filename|>Runtime/UI/Component/ScrollView/LoopScrollPrefabSource.cs<|end_filename|>
﻿using UnityEngine;
using Framework.Pool;

namespace Framework.UI
{
    [System.Serializable]
    public class LoopScrollPrefabSource
    {
        public GameObject Prefab;
        public int PoolSize = 5;
        private PrefabPool pool;
        private Transform root;

        public void Init(Transform scrollRect)
        {
            root = new GameObject("Pool").transform;
            root.SetParent(scrollRect, false);
            pool = new PrefabPool(Prefab, PoolSize,
                onFree: o => o.transform.SetParent(root, false));
        }
        
        public virtual GameObject GetObject()
        {
            return pool.Allocate();
        }

        public virtual void ReturnObject(Transform go)
        {
            pool.Free(go.gameObject);
        }
    }
}


<|start_filename|>Runtime/Tool/Net/Http/UnityWebRequestFileDownloader.cs<|end_filename|>
﻿/*
/*
 * MIT License
 *
 * Copyright (c) 2018 <NAME>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of 
 * this software and associated documentation files (the "Software"), to deal in 
 * the Software without restriction, including without limitation the rights to 
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
 * of the Software, and to permit persons to whom the Software is furnished to do so, 
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all 
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
 * SOFTWARE.
 #1#
*/
using System;
using System.IO;
using System.Collections;
using UnityEngine.Networking;
using System.Collections.Generic;
using Framework.Asynchronous;
using UnityEngine;

namespace Framework.Net
{
    public class UnityWebRequestFileDownloader : FileDownloaderBase
    {
        public override IProgressResult<ProgressInfo, FileInfo> DownloadFileAsync(string path, FileInfo fileInfo, float overtimeTime = 50)
        {
            return Execution.Executors.RunOnCoroutine<ProgressInfo, FileInfo>((promise) =>
                DoDownloadFileAsync(path, fileInfo, promise, overtimeTime));
        }

        protected virtual IEnumerator DoDownloadFileAsync(string path, FileInfo fileInfo,
            IProgressPromise<ProgressInfo> promise, float overtimeTime)
        {
            if (fileInfo.Directory != null && !fileInfo.Directory.Exists)
                fileInfo.Directory.Create();
            ProgressInfo progressInfo = new ProgressInfo {TotalCount = 1};
            using (UnityWebRequest www = new UnityWebRequest(path))
            {
                var downloadFileHandler = new DownloadFileHandler(fileInfo);
                www.downloadHandler = downloadFileHandler;
                www.SendWebRequest();
                float timer = 0;
                while (!www.isDone)
                {
                    if (www.downloadProgress >= 0)
                    {
                        if (progressInfo.TotalSize <= 0)
                            progressInfo.TotalSize = (long) (www.downloadedBytes / www.downloadProgress);
                        progressInfo.CompletedSize = (long) www.downloadedBytes;
                        promise.UpdateProgress(progressInfo);
                    }
                    timer += Time.deltaTime;
                    if (timer > overtimeTime)
                    {
                        promise.SetException(new TimeoutException());
                        break;
                    }
                    yield return null;
                }

                while (!downloadFileHandler.WriteFinish)
                {
                    timer += Time.deltaTime;
                    if (timer > overtimeTime)
                    {
                        promise.SetException(new TimeoutException());
                        break;
                    }
                    yield return null;
                }
                
                if(www.isNetworkError || www.isHttpError)
                {
                    promise.SetException(www.error);
                    yield break;
                }
                
                progressInfo.CompletedCount = 1;
                progressInfo.CompletedSize = progressInfo.TotalSize;
                promise.UpdateProgress(progressInfo);
                promise.SetResult(fileInfo);
            }
        }

        public override IProgressResult<ProgressInfo, ResourceInfo[]> DownloadFileAsync(ResourceInfo[] infos)
        {
            return Execution.Executors.RunOnCoroutine<ProgressInfo, ResourceInfo[]>((promise) =>
                DoDownloadFileAsync(infos, promise));
        }

        protected virtual IEnumerator DoDownloadFileAsync(ResourceInfo[] infos, IProgressPromise<ProgressInfo> promise)
        {
            long totalSize = 0;
            long downloadedSize = 0;
            List<ResourceInfo> downloadList = new List<ResourceInfo>();
            foreach (var info in infos)
            {
                var fileInfo = info.FileInfo;

                if (info.FileSize < 0)
                {
                    if (fileInfo.Exists)
                    {
                        info.FileSize = fileInfo.Length;
                    }
                    else
                    {
                        using (UnityWebRequest www = UnityWebRequest.Head(info.Path))
                        {
                            yield return www.SendWebRequest();
                            string contentLength = www.GetResponseHeader("Content-Length");
                            if (!string.IsNullOrEmpty(contentLength))
                                info.FileSize = long.Parse(contentLength);
                        }
                    }
                }

                totalSize += info.FileSize;
                if (fileInfo.Exists)
                    downloadedSize += info.FileSize;
                else
                    downloadList.Add(info);
            }

            ProgressInfo progressInfo = new ProgressInfo
            {
                TotalCount = infos.Length,
                CompletedCount = infos.Length - downloadList.Count,
                TotalSize = totalSize,
                CompletedSize = downloadedSize
            };

            yield return null;

            List<KeyValuePair<ResourceInfo, UnityWebRequest>> tasks =
                new List<KeyValuePair<ResourceInfo, UnityWebRequest>>();
            for (int i = 0; i < downloadList.Count; i++)
            {
                ResourceInfo info = downloadList[i];
                var path = info.Path;
                FileInfo fileInfo = info.FileInfo;
                if (fileInfo.Directory != null && !fileInfo.Directory.Exists)
                    fileInfo.Directory.Create();

                UnityWebRequest www = new UnityWebRequest(path);
                www.downloadHandler = new DownloadFileHandler(fileInfo);

                www.SendWebRequest();
                tasks.Add(new KeyValuePair<ResourceInfo, UnityWebRequest>(info, www));

                while (tasks.Count >= this.MaxTaskCount || (i == downloadList.Count - 1 && tasks.Count > 0))
                {
                    long tmpSize = 0;
                    for (int j = tasks.Count - 1; j >= 0; j--)
                    {
                        var task = tasks[j];
                        ResourceInfo _info = task.Key;
                        UnityWebRequest _www = task.Value;

                        if (!_www.isDone)
                        {
                            tmpSize += (long) Math.Max(0,
                                _www.downloadedBytes); //the UnityWebRequest.downloadedProgress has a bug in android platform
                            continue;
                        }

                        progressInfo.CompletedCount += 1;
                        tasks.RemoveAt(j);
                        downloadedSize += _info.FileSize;
                        if (_www.isNetworkError || _www.isHttpError)
                        {
                            promise.SetException(new Exception(_www.error));
                            Log.Error(
                                $"Downloads file '{_info.FileInfo.FullName}' failure from the address '{(_info.Path)}'.Reason:{_www.error}");
                            _www.Dispose();

                            try
                            {
                                foreach (var kv in tasks)
                                {
                                    kv.Value.Dispose();
                                }
                            }
                            catch (Exception)
                            {
                            }

                            yield break;
                        }

                        _www.Dispose();
                    }

                    progressInfo.CompletedSize = downloadedSize + tmpSize;
                    promise.UpdateProgress(progressInfo);
                    yield return null;
                }
            }

            promise.SetResult(infos);
        }
    }
}


<|start_filename|>Runtime/Execution/ITimerExecutor.cs<|end_filename|>
﻿/*
 * MIT License
 *
 * Copyright (c) 2018 <NAME>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of 
 * this software and associated documentation files (the "Software"), to deal in 
 * the Software without restriction, including without limitation the rights to 
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
 * of the Software, and to permit persons to whom the Software is furnished to do so, 
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all 
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
 * SOFTWARE.
 */

using System;
using Framework.Asynchronous;

namespace Framework.Execution
{
    public interface ITimerExecutor : IDisposable
    {
        /// <summary>
        /// Start the service.
        /// </summary>
        void Start();

        /// <summary>
        /// Stop the service.
        /// </summary>
        void Stop();

        /// <summary>
        /// Creates and executes a task that becomes enabled after the given delay.
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="command"></param>
        /// <param name="delay">millisecond</param>
        /// <returns></returns>
        IAsyncResult<TResult> Delay<TResult>(Func<TResult> command, long delay);

        /// <summary>
        /// Creates and executes a task that becomes enabled after the given delay.
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="command"></param>
        /// <param name="delay"></param>
        /// <returns></returns>
        IAsyncResult<TResult> Delay<TResult>(Func<TResult> command, TimeSpan delay);

        /// <summary>
        /// Creates and executes a one-shot action that becomes enabled after the given delay.
        /// </summary>
        /// <param name="command"></param>
        /// <param name="delay">millisecond</param>
        /// <returns></returns>
        Asynchronous.IAsyncResult Delay(Action command, long delay);

        /// <summary>
        /// Creates and executes a one-shot action that becomes enabled after the given delay.
        /// </summary>
        /// <param name="command"></param>
        /// <param name="delay"></param>
        /// <returns></returns>
        Asynchronous.IAsyncResult Delay(Action command, TimeSpan delay);

        /// <summary>
        /// Creates and executes a periodic action that becomes enabled first after the given initial delay, and subsequently with the given period; that is executions will commence after initialDelay then initialDelay+period, then initialDelay + 2 * period, and so on.
        /// </summary>
        /// <param name="command"></param>
        /// <param name="initialDelay">millisecond</param>
        /// <param name="period">millisecond</param>
        /// <returns></returns>
        Asynchronous.IAsyncResult FixedRate(Action command, long initialDelay, long period);

        /// <summary>
        /// Creates and executes a periodic action that becomes enabled first after the given initial delay, and subsequently with the given period; that is executions will commence after initialDelay then initialDelay+period, then initialDelay + 2 * period, and so on.
        /// </summary>
        /// <param name="command"></param>
        /// <param name="initialDelay"></param>
        /// <param name="period"></param>
        /// <returns></returns>
        Asynchronous.IAsyncResult FixedRate(Action command, TimeSpan initialDelay, TimeSpan period);

        /// <summary>
        /// Creates and executes a periodic action that becomes enabled first after the given initial delay, and subsequently with the given period; that is executions will commence after initialDelay then initialDelay+period, then initialDelay + 2 * period, and so on.
        /// </summary>
        /// <param name="fixedUpdateCommand">call per fixed rate</param>
        /// <param name="endCommand">end call</param>
        /// <param name="initialDelay">millisecond</param>
        /// <param name="period">millisecond</param>
        /// <param name="duration">millisecond</param>
        /// <returns></returns>
        Asynchronous.IAsyncResult FixedRateAtDuration(Action<long> fixedUpdateCommand, Action endCommand = null, long? initialDelay = null, long? period = null, long? duration = null);

        /// <summary>
        /// Creates and executes a periodic action that becomes enabled first after the given initial delay, and subsequently with the given period; that is executions will commence after initialDelay then initialDelay+period, then initialDelay + 2 * period, and so on.
        /// </summary>
        /// <param name="fixedUpdateCommand">call per fixed rate</param>
        /// <param name="endCommand">end call</param>
        /// <param name="initialDelay"></param>
        /// <param name="period"></param>
        /// <param name="duration"></param>
        /// <returns></returns>
        Asynchronous.IAsyncResult FixedRateAtDuration(Action<long> fixedUpdateCommand, Action endCommand, TimeSpan? initialDelay, TimeSpan? period, TimeSpan? duration);

    }
}


<|start_filename|>Tests/Runtime/AsyncCoroutine.cs<|end_filename|>
﻿using System;
using System.Collections;
using System.Threading;
using System.Threading.Tasks;
using Framework.Asynchronous;
using Framework.Execution;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.TestTools;

namespace Tests
{
    public class AsyncCoroutineTest
    {
        private int mainThreadId;

        //IThreadPoolWorkItem, IAsyncResult,
        [UnityTest]
        public IEnumerator AwaitTest()
        {
            bool isComplete = false;
            AwaitTest1(() => isComplete = true);
            while (!isComplete)
            {
                yield return null;
            }
        }
        public async void AwaitTest1(Action complete)
        {
            mainThreadId = Thread.CurrentThread.ManagedThreadId;
            float timer = Time.time;
            await new WaitForSeconds(0.1f);
            timer += 0.1f;
            Assert.IsTrue(Mathf.Abs(Time.time - timer) <= 0.1f);

            await Task.Delay(100);
            timer += 0.1f;
            Assert.IsTrue(Mathf.Abs(Time.time - timer) <= 0.1f);

            UnityWebRequest www = await UnityWebRequest.Get("http://www.baidu.com").SendWebRequest();
            
            Assert.IsFalse(www.isHttpError);
            Assert.IsFalse(www.isNetworkError);
            if (!www.isHttpError && !www.isNetworkError)
                Debug.Log(www.downloadHandler.text);
            timer = Time.time;
            
            //切换到另一个线程
            float result = await Calculate();
            timer += result / 1000;
            Assert.IsTrue(mainThreadId != Thread.CurrentThread.ManagedThreadId);
            Debug.Log($"async thread : {Thread.CurrentThread.ManagedThreadId}");

            //切换到主线程
            await new WaitForMainThread();
            Assert.IsTrue(mainThreadId == Thread.CurrentThread.ManagedThreadId);
            Debug.LogFormat("Switch to the main thread,Current Thread ID:{0}", Thread.CurrentThread.ManagedThreadId);

            await new WaitForSecondsRealtime(0.1f);
            timer += 0.1f;
            Assert.IsTrue(Mathf.Abs(Time.time - timer) <= 0.1f);

            await DoTask(5);
            timer += 0.1f;
            Assert.IsTrue(Mathf.Abs(Time.time - timer) <= 0.1f);
            complete();
        }
        
        IAsyncResult<float> Calculate()
        {
            return Executors.RunAsync(() =>
            {
                Assert.IsTrue(mainThreadId != Thread.CurrentThread.ManagedThreadId);
                float total = 0;
                for (int i = 0; i < 20; i++)
                {
                    try
                    {
                        Thread.Sleep(10);
                    }
                    catch (Exception) { }
                }
                total += 20 * 10;
                return total;
            });
        }
        
        IEnumerator DoTask(int n)
        {
            yield return new WaitForSeconds(0.1f);

            for (int i = 0; i < n; i++)
            {
                yield return null;
            }
        }
    }
}

<|start_filename|>Runtime/UI/Wrap/Base/IBindList.cs<|end_filename|>
﻿using System;
using System.Collections.Specialized;

namespace Framework.UI.Wrap.Base
{
    public interface IBindList<T>
    {
        Action<NotifyCollectionChangedAction, T, int> GetBindListFunc();
    }
}

<|start_filename|>Runtime/UI/Wrap/ImageWrapper.cs<|end_filename|>
﻿using System;
using Framework.Assets;
using Framework.UI.Core;
using Framework.UI.Wrap.Base;
using UnityEngine;
using UnityEngine.UI;

namespace Framework.UI.Wrap
{
    public class ImageWrapper : BaseWrapper<Image>, IFieldChangeCb<string>
    {

        Action<string> IFieldChangeCb<string>.GetFieldChangeCb()
        {
            return path =>
            {
                if(string.IsNullOrEmpty(path)) return;
                IRes res = null;
                if (Container is ICustomRes customRes)
                {
                    res = customRes.GetRes();
                }
                else
                {
                    res = Res.Default;
                }
                res.LoadAssetAsync<Sprite>(path).Callbackable()
                    .OnCallback(result =>
                    {
                        if(result.IsCancelled) return;
                        if (Component != null)
                        {
                            Component.sprite = result.Result;
                        }
                    });
            };
        }

        public ImageWrapper(Image component, View view) : base(component, view)
        {
        }
    }
}

<|start_filename|>Runtime/UI/Wrap/ViewWrapper.cs<|end_filename|>
﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using Framework.Assets;
using Framework.Asynchronous;
using Framework.UI.Core;
using Framework.UI.Core.Bind;
using Framework.UI.Wrap.Base;
using Tool;
using UnityEngine;
using Object = UnityEngine.Object;

namespace Framework.UI.Wrap
{
    public class ViewWrapper: BaseWrapper<View>, IBindList<ViewModel>
    {
        private readonly Transform _content;
        private readonly View _item;
        private readonly GameObject _template;
        private List<View> existViews = new List<View>();
        private int _tag;
        private int _index;

        public ViewWrapper(View component, Transform root, int index = 0) : base(component, component)
        {
            _item = component;
            _content = root;
            Log.Assert(_content.childCount == 1 , "_content.childCount 只能有一个");
            _template = _content.GetChild(0).gameObject;
            _template.ActiveHide();
            _tag = 0;
            _index = index;
        }

        public void SetTag(int tag)
        {
            this._tag = tag;
        }

        Action<NotifyCollectionChangedAction, ViewModel, int> IBindList<ViewModel>.GetBindListFunc()
        {
            return BindListFunc;
        }

        private void BindListFunc
            (NotifyCollectionChangedAction type, ViewModel newViewModel, int index)
        {
            var tag = GetTag(newViewModel);
            if (tag != this._tag) return;
            switch (type)
            {
                case NotifyCollectionChangedAction.Add:
                    AddItem(index, newViewModel);
                    break;
                case NotifyCollectionChangedAction.Remove:
                    RemoveItem(index);
                    break;
                case NotifyCollectionChangedAction.Replace:
                    ReplaceItem(index, newViewModel);
                    break;
                case NotifyCollectionChangedAction.Reset:
                    Clear(index);
                    break;
                case NotifyCollectionChangedAction.Move: break;
                default: throw new ArgumentOutOfRangeException(nameof(type), type, null);
            }
        }

        private void AddItem(int index, ViewModel vm)
        {
            var view = ReflectionHelper.CreateInstance(_item.GetCLRType()) as View;
            var go = Object.Instantiate(_template, _content);
            go.transform.SetSiblingIndex(index + 1);
            go.ActiveShow();
            view.SetGameObject(go);
            view.SetVm(vm);
            view.Show();
            existViews.Insert(index, view);
        }

        private void RemoveItem(int index)
        {
            Object.DestroyImmediate(_content.GetChild(index+1).gameObject);
            existViews.RemoveAt(index);
        }

        private void ReplaceItem(int index, ViewModel vm)
        {
            existViews[index].SetVm(vm);
        }

        private void Clear(int itemCount)
        {
            while (itemCount > 0)
            {
                RemoveItem(--itemCount);
            }
            existViews.Clear();
        }

        private static int GetTag(ViewModel vm)
        {
            var _vm = vm as IBindMulView;
            if (_vm == null) return 0;
            return _vm.Tag;
        }
    }
}

<|start_filename|>Runtime/UI/Wrap/Base/IBindDic.cs<|end_filename|>
﻿using System.Collections.Specialized;

namespace Framework.UI.Wrap.Base
{
    public interface IBindDic
    {
        NotifyCollectionChangedEventHandler GetBindDicFunc();
    }
}

<|start_filename|>Runtime/Asynchronous/Synchronizable.cs<|end_filename|>
﻿/*
 * MIT License
 *
 * Copyright (c) 2018 <NAME>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of 
 * this software and associated documentation files (the "Software"), to deal in 
 * the Software without restriction, including without limitation the rights to 
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
 * of the Software, and to permit persons to whom the Software is furnished to do so, 
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all 
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
 * SOFTWARE.
 */

using System;
using System.Threading;

namespace Framework.Asynchronous
{
    public interface ISynchronizable
    {
        /// <summary>
        ///  Wait for done,will block the current thread.
        /// </summary>
        /// <returns></returns>
        bool WaitForDone();

        /// <summary>
        /// Wait for the result,will block the current thread.
        /// </summary>
        /// <param name="millisecondsTimeout"></param>
        /// <exception cref="TimeoutException"></exception>
        /// <exception cref="Exception"></exception>
        /// <returns></returns>
        object WaitForResult(int millisecondsTimeout = 0);

        /// <summary>
        ///  Wait for the result,will block the current thread.
        /// </summary>
        /// <param name="timeout"></param>
        /// <exception cref="TimeoutException"></exception>
        /// <exception cref="Exception"></exception>
        /// <returns></returns>
        object WaitForResult(TimeSpan timeout);
    }

    public interface ISynchronizable<TResult> : ISynchronizable
    {
        /// <summary>
        /// Wait for the result,will block the current thread.
        /// </summary>
        /// <param name="millisecondsTimeout"></param>
        /// <exception cref="TimeoutException"></exception>
        /// <exception cref="Exception"></exception>
        /// <returns></returns>
        new TResult WaitForResult(int millisecondsTimeout = 0);

        /// <summary>
        /// Wait for the result,will block the current thread.
        /// </summary>
        /// <param name="timeout"></param>
        /// <exception cref="TimeoutException"></exception>
        /// <exception cref="Exception"></exception>
        /// <returns></returns>
        new TResult WaitForResult(TimeSpan timeout);
    }

    internal class Synchronizable : ISynchronizable
    {
        private readonly IAsyncResult _result;
        private readonly object _lock;

        public Synchronizable(IAsyncResult result, object @lock)
        {
            this._result = result;
            this._lock = @lock;
        }

        /// <summary>
        /// Wait for done,will block the current thread.
        /// </summary>
        /// <returns></returns>
        public bool WaitForDone()
        {
            if (_result.IsDone)
                return _result.IsDone;

            lock (_lock)
            {
                if (!_result.IsDone)
                    Monitor.Wait(_lock);
            }

            return _result.IsDone;
        }

        /// <summary>
        /// Wait for the result,will block the current thread.
        /// </summary>
        /// <param name="millisecondsTimeout"></param>
        /// <exception cref="TimeoutException"></exception>
        /// <exception cref="Exception"></exception>
        /// <returns></returns>
        public object WaitForResult(int millisecondsTimeout = 0)
        {
            if (_result.IsDone)
            {
                if (_result.Exception != null)
                    throw _result.Exception;

                return _result.Result;
            }

            lock (_lock)
            {
                if (!_result.IsDone)
                {
                    if (millisecondsTimeout > 0)
                        Monitor.Wait(_lock, millisecondsTimeout);
                    else
                        Monitor.Wait(_lock);
                }
            }

            if (!_result.IsDone)
                throw new TimeoutException();

            if (_result.Exception != null)
                throw _result.Exception;

            return _result.Result;
        }

        /// <summary>
        ///  Wait for the result,will block the current thread.
        /// </summary>
        /// <param name="timeout"></param>
        /// <exception cref="TimeoutException"></exception>
        /// <exception cref="Exception"></exception>
        /// <returns></returns>
        public object WaitForResult(TimeSpan timeout)
        {
            if (_result.IsDone)
            {
                if (_result.Exception != null)
                    throw _result.Exception;

                return _result.Result;
            }

            lock (_lock)
            {
                if (!_result.IsDone)
                {
                    Monitor.Wait(_lock, timeout);
                }
            }

            if (!_result.IsDone)
                throw new TimeoutException();

            if (_result.Exception != null)
                throw _result.Exception;

            return _result.Result;
        }
    }

    internal class Synchronizable<TResult> : ISynchronizable<TResult>
    {
        //private static readonly ILog log = LogManager.GetLogger(typeof(Synchronizable<TResult>));

        private readonly IAsyncResult<TResult> _result;
        private readonly object _lock;

        public Synchronizable(IAsyncResult<TResult> result, object @lock)
        {
            this._result = result;
            this._lock = @lock;
        }

        /// <summary>
        /// Wait for done,will block the current thread.
        /// </summary>
        /// <returns></returns>
        public bool WaitForDone()
        {
            if (_result.IsDone)
                return _result.IsDone;

            lock (_lock)
            {
                if (!_result.IsDone)
                    Monitor.Wait(_lock);
            }

            return _result.IsDone;
        }

        /// <summary>
        /// Wait for the result,will block the current thread.
        /// </summary>
        /// <param name="millisecondsTimeout"></param>
        /// <exception cref="TimeoutException"></exception>
        /// <exception cref="Exception"></exception>
        /// <returns></returns>
        public TResult WaitForResult(int millisecondsTimeout = 0)
        {
            if (_result.IsDone)
            {
                if (_result.Exception != null)
                    throw _result.Exception;

                return _result.Result;
            }

            lock (_lock)
            {
                if (!_result.IsDone)
                {
                    if (millisecondsTimeout > 0)
                        Monitor.Wait(_lock, millisecondsTimeout);
                    else
                        Monitor.Wait(_lock);
                }
            }

            if (!_result.IsDone)
                throw new TimeoutException();

            if (_result.Exception != null)
                throw _result.Exception;

            return _result.Result;
        }

        /// <summary>
        /// Wait for the result,will block the current thread.
        /// </summary>
        /// <param name="timeout"></param>
        /// <exception cref="TimeoutException"></exception>
        /// <exception cref="Exception"></exception>
        /// <returns></returns>
        public TResult WaitForResult(TimeSpan timeout)
        {
            if (_result.IsDone)
            {
                if (_result.Exception != null)
                    throw _result.Exception;

                return _result.Result;
            }

            lock (_lock)
            {
                if (!_result.IsDone)
                {
                    Monitor.Wait(_lock, timeout);
                }
            }

            if (!_result.IsDone)
                throw new TimeoutException();

            if (_result.Exception != null)
                throw _result.Exception;

            return _result.Result;
        }

        object ISynchronizable.WaitForResult(int millisecondsTimeout)
        {
            return WaitForResult(millisecondsTimeout);
        }

        object ISynchronizable.WaitForResult(TimeSpan timeout)
        {
            return WaitForResult(timeout);
        }
    }
}


<|start_filename|>Runtime/UI/Wrap/Base/IComponentEvent.cs<|end_filename|>
﻿using UnityEngine.Events;

namespace Framework.UI.Wrap.Base
{
    public interface IComponentEvent<T>
    {
        UnityEvent<T> GetComponentEvent();
    }

    public interface IComponentEvent
    {
        UnityEvent GetComponentEvent();
    }
}

<|start_filename|>Runtime/Asynchronous/AsyncTask.cs<|end_filename|>
﻿/*
 * MIT License
 *
 * Copyright (c) 2018 <NAME>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of 
 * this software and associated documentation files (the "Software"), to deal in 
 * the Software without restriction, including without limitation the rights to 
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
 * of the Software, and to permit persons to whom the Software is furnished to do so, 
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all 
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
 * SOFTWARE.
 */

using System;
using System.Threading;
using System.Collections;
using Framework.Execution;

namespace Framework.Asynchronous
{
    public class AsyncTask : IAsyncTask
    {
        private readonly Action _action;

        private Action _preCallbackOnMainThread;
        private Action _preCallbackOnWorkerThread;

        //no exception call
        private Action _postCallbackOnMainThread;
        private Action _postCallbackOnWorkerThread;

        private Action<Exception> _errorCallbackOnMainThread;
        private Action<Exception> _errorCallbackOnWorkerThread;

        //always call
        private Action _finishCallbackOnMainThread;
        private Action _finishCallbackOnWorkerThread;

        private int _running;
        private readonly AsyncResult _result;

        /// <summary>
        ///
        /// </summary>
        /// <param name="task"></param>
        /// <param name="runOnMainThread"></param>
        public AsyncTask(Action task, bool runOnMainThread = false)
        {
            if (task == null)
                throw new ArgumentNullException(nameof(task));

            this._result = new AsyncResult();
            if (runOnMainThread)
            {
                this._action = WrapAction(() =>
                {
                    Executors.RunOnMainThread(task, true);
                    this._result.SetResult();
                });
            }
            else
            {
                this._action = WrapAction(() =>
                {
                    task();
                    this._result.SetResult();
                });
            }
        }

        public AsyncTask(Action<IPromise> task, bool runOnMainThread = false, bool cancelable = false)
        {
            if (task == null)
                throw new ArgumentNullException(nameof(task));

            this._result = new AsyncResult(!runOnMainThread && cancelable);
            if (runOnMainThread)
            {
                this._action = WrapAction(() =>
                {
                    Executors.RunOnMainThread(() => task(_result), true);
                    this._result.Synchronized().WaitForResult();
                });
            }
            else
            {
                this._action = WrapAction(() =>
                {
                    task(_result);
                    this._result.Synchronized().WaitForResult();
                });
            }
        }

        /// <summary>
        /// run on main thread
        /// </summary>
        public AsyncTask(IEnumerator task, bool cancelable = false)
        {
            if (task == null)
                throw new ArgumentNullException(nameof(task));

            this._result = new AsyncResult(cancelable);
            this._action = WrapAction(() =>
            {
                Executors.RunOnCoroutine(task, _result);
                this._result.Synchronized().WaitForResult();
            });
        }

        public virtual object Result => this._result.Result;

        public virtual Exception Exception => this._result.Exception;

        public virtual bool IsDone => this._result.IsDone && this._running == 0;

        public virtual bool IsCancelled => this._result.IsCancelled;

        protected virtual Action WrapAction(Action action)
        {
            void WrapFunc()
            {
                try
                {
                    try
                    {
                        _preCallbackOnWorkerThread?.Invoke();
                    }
                    catch (Exception e)
                    {
                        Log.Warning(e);
                    }

                    if (this._result.IsCancellationRequested)
                    {
                        this._result.SetCancelled();
                        return;
                    }

                    action();
                }
                catch (Exception e)
                {
                    this._result.SetException(e);
                }
                finally
                {
                    try
                    {
                        if (this.Exception != null)
                        {
                            if (this._errorCallbackOnMainThread != null)
                                Executors.RunOnMainThread(() => this._errorCallbackOnMainThread(this.Exception), true);

                            _errorCallbackOnWorkerThread?.Invoke(this.Exception);
                        }
                        else
                        {
                            if (this._postCallbackOnMainThread != null)
                                Executors.RunOnMainThread(this._postCallbackOnMainThread, true);

                            _postCallbackOnWorkerThread?.Invoke();
                        }
                    }
                    catch (Exception e)
                    {
                        Log.Warning(e);
                    }

                    try
                    {
                        if (this._finishCallbackOnMainThread != null)
                            Executors.RunOnMainThread(this._finishCallbackOnMainThread, true);

                        _finishCallbackOnWorkerThread?.Invoke();
                    }
                    catch (Exception e)
                    {
                        Log.Warning(e);
                    }

                    Interlocked.Exchange(ref this._running, 0);
                }
            }

            return WrapFunc;
        }

        public virtual bool Cancel()
        {
            return this._result.Cancel();
        }

        public virtual ICallbackable Callbackable()
        {
            return _result.Callbackable();
        }

        public virtual ISynchronizable Synchronized()
        {
            return _result.Synchronized();
        }

        public virtual object WaitForDone()
        {
            return Executors.WaitWhile(() => !IsDone);
        }

        public IAsyncTask OnPreExecute(Action callback, bool runOnMainThread = true)
        {
            if (runOnMainThread)
                this._preCallbackOnMainThread += callback;
            else
                this._preCallbackOnWorkerThread += callback;
            return this;
        }

        public IAsyncTask OnPostExecute(Action callback, bool runOnMainThread = true)
        {
            if (runOnMainThread)
                this._postCallbackOnMainThread += callback;
            else
                this._postCallbackOnWorkerThread += callback;
            return this;
        }

        public IAsyncTask OnError(Action<Exception> callback, bool runOnMainThread = true)
        {
            if (runOnMainThread)
                this._errorCallbackOnMainThread += callback;
            else
                this._errorCallbackOnWorkerThread += callback;
            return this;
        }

        public IAsyncTask OnFinish(Action callback, bool runOnMainThread = true)
        {
            if (runOnMainThread)
                this._finishCallbackOnMainThread += callback;
            else
                this._finishCallbackOnWorkerThread += callback;
            return this;
        }

        public IAsyncTask Start(int delay)
        {
            if (delay <= 0)
                return this.Start();

            Executors.RunAsync(() =>
            {
                Thread.Sleep(delay);
                if (this.IsDone || this._running == 1)
                    return;

                this.Start();
            });
            return this;
        }

        public IAsyncTask Start()
        {
            if (this.IsDone)
            {
                Log.Warning("The task has been done!");
                return this;
            }

            if (_running == 1)
            {
                Log.Warning("The task is running!");
                return this;
            }

            try
            {
                if (this._preCallbackOnMainThread != null)
                    Executors.RunOnMainThread(this._preCallbackOnMainThread, true);
            }
            catch (Exception e)
            {
                Log.Warning(e);
            }

            Executors.RunAsync(this._action);

            return this;
        }
    }

    public class AsyncTask<TResult> : IAsyncTask<TResult>
    {

        private readonly Action _action;

        private Action _preCallbackOnMainThread;
        private Action _preCallbackOnWorkerThread;

        private Action<TResult> _postCallbackOnMainThread;
        private Action<TResult> _postCallbackOnWorkerThread;

        private Action<Exception> _errorCallbackOnMainThread;
        private Action<Exception> _errorCallbackOnWorkerThread;

        private Action _finishCallbackOnMainThread;
        private Action _finishCallbackOnWorkerThread;

        private int _running = 0;
        private readonly AsyncResult<TResult> _result;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="task"></param>
        /// <param name="runOnMainThread"></param>
        public AsyncTask(Func<TResult> task, bool runOnMainThread = false)
        {
            if (task == null)
                throw new ArgumentNullException();

            this._result = new AsyncResult<TResult>();

            if (runOnMainThread)
            {
                this._action = WrapAction(() => Executors.RunOnMainThread(task));
            }
            else
            {
                this._action = WrapAction(task);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="task"></param>
        /// <param name="runOnMainThread"></param>
        public AsyncTask(Action<IPromise<TResult>> task, bool runOnMainThread = false, bool cancelable = false)
        {
            if (task == null)
                throw new ArgumentNullException();

            this._result = new AsyncResult<TResult>(!runOnMainThread && cancelable);

            if (runOnMainThread)
            {
                this._action = WrapAction(() =>
                {
                    Executors.RunOnMainThread(() => task(this._result));
                    return this._result.Synchronized().WaitForResult();
                });
            }
            else
            {
                this._action = WrapAction(() =>
                {
                    task(this._result);
                    return this._result.Synchronized().WaitForResult();
                });
            }
        }

        public AsyncTask(Func<IPromise<TResult>, IEnumerator> task, bool cancelable = false)
        {
            if (task == null)
                throw new ArgumentNullException();

            this._result = new AsyncResult<TResult>(cancelable);
            this._action = WrapAction(() =>
            {
                Executors.RunOnCoroutine(task(this._result), this._result);
                return this._result.Synchronized().WaitForResult();
            });
        }

        public virtual TResult Result => this._result.Result;

        object Asynchronous.IAsyncResult.Result => this._result.Result;

        public virtual Exception Exception => this._result.Exception;

        public virtual bool IsDone => this._result.IsDone && this._running == 0;

        public virtual bool IsCancelled => this._result.IsCancelled;

        protected virtual Action WrapAction(Func<TResult> action)
        {
            void WrapFunc()
            {
                try
                {
                    try
                    {
                        _preCallbackOnWorkerThread?.Invoke();
                    }
                    catch (Exception e)
                    {
                        Log.Warning(e);
                    }

                    if (this._result.IsCancellationRequested)
                    {
                        this._result.SetCancelled();
                        return;
                    }

                    TResult obj = action();
                    this._result.SetResult(obj);
                }
                catch (Exception e)
                {
                    this._result.SetException(e);
                }
                finally
                {
                    try
                    {
                        if (this.Exception != null)
                        {
                            if (this._errorCallbackOnMainThread != null)
                                Executors.RunOnMainThread(() => this._errorCallbackOnMainThread(this.Exception), true);

                            _errorCallbackOnWorkerThread?.Invoke(this.Exception);
                        }
                        else
                        {
                            if (this._postCallbackOnMainThread != null)
                                Executors.RunOnMainThread(() => this._postCallbackOnMainThread(this.Result), true);

                            _postCallbackOnWorkerThread?.Invoke(this.Result);
                        }
                    }
                    catch (Exception e)
                    {
                        Log.Warning(e);
                    }

                    try
                    {
                        if (this._finishCallbackOnMainThread != null)
                            Executors.RunOnMainThread(this._finishCallbackOnMainThread, true);

                        _finishCallbackOnWorkerThread?.Invoke();
                    }
                    catch (Exception e)
                    {
                        Log.Warning(e);
                    }

                    Interlocked.Exchange(ref this._running, 0);
                }
            }

            return WrapFunc;
        }

        public virtual bool Cancel()
        {
            return this._result.Cancel();
        }

        public virtual ICallbackable<TResult> Callbackable()
        {
            return _result.Callbackable();
        }

        public virtual ISynchronizable<TResult> Synchronized()
        {
            return _result.Synchronized();
        }

        ICallbackable IAsyncResult.Callbackable()
        {
            return (_result as IAsyncResult).Callbackable();
        }

        ISynchronizable IAsyncResult.Synchronized()
        {
            return (_result as IAsyncResult).Synchronized();
        }

        public virtual object WaitForDone()
        {
            return Executors.WaitWhile(() => !IsDone);
        }

        public IAsyncTask<TResult> OnPreExecute(Action callback, bool runOnMainThread = true)
        {
            if (runOnMainThread)
                this._preCallbackOnMainThread += callback;
            else
                this._preCallbackOnWorkerThread += callback;
            return this;
        }

        public IAsyncTask<TResult> OnPostExecute(Action<TResult> callback, bool runOnMainThread = true)
        {
            if (runOnMainThread)
                this._postCallbackOnMainThread += callback;
            else
                this._postCallbackOnWorkerThread += callback;
            return this;
        }

        public IAsyncTask<TResult> OnError(Action<Exception> callback, bool runOnMainThread = true)
        {
            if (runOnMainThread)
                this._errorCallbackOnMainThread += callback;
            else
                this._errorCallbackOnWorkerThread += callback;
            return this;
        }

        public IAsyncTask<TResult> OnFinish(Action callback, bool runOnMainThread = true)
        {
            if (runOnMainThread)
                this._finishCallbackOnMainThread += callback;
            else
                this._finishCallbackOnWorkerThread += callback;
            return this;
        }

        public IAsyncTask<TResult> Start(int delay)
        {
            if (delay <= 0)
                return this.Start();
            Thread.Sleep(delay);
            Executors.RunAsync(() =>
            {
                if (this.IsDone || this._running == 1)
                    return;

                this.Start();
            });

            return this;
        }

        public IAsyncTask<TResult> Start()
        {
            if (this.IsDone)
            {
                Log.Warning("The task has been done!");
                return this;
            }


            if (_running == 1)
            {
                Log.Warning("The task is running!");
                return this;
            }

            try
            {
                if (this._preCallbackOnMainThread != null)
                    Executors.RunOnMainThread(this._preCallbackOnMainThread, true);
            }
            catch (Exception e)
            {
                Log.Warning(e);
            }

            Executors.RunAsync(this._action);

            return this;
        }
    }
}

<|start_filename|>Runtime/Manager/ConfigAttribute.cs<|end_filename|>
    using Framework;

    public class ConfigAttribute : ManagerAttribute
    {
        public string Path { get; private set; }
        
        public ConfigAttribute(string path) : base(0)
        {
            Path = path;
        }

        public override string IndexName { get; } = nameof(Path);
    }
