• LuaFramework 学习


    LuaFramework_UGUI_V2  https://github.com/jarjin/LuaFramework_UGUI_V2

    using UnityEngine;
    using LuaInterface;
    using System.Collections;
    using System.Collections.Generic;
    using System;
    using UnityEngine.UI;
    
    namespace LuaFramework {
        public class LuaBehaviour : View {
            private string data = null;
            private Dictionary<string, LuaFunction> buttons = new Dictionary<string, LuaFunction>();
    
            protected void Awake() {
                Util.CallMethod(name, "Awake", gameObject);
            }
    
            protected void Start() {
                Util.CallMethod(name, "Start");
            }
    
            protected void OnClick() {
                Util.CallMethod(name, "OnClick");
            }
    
            protected void OnClickEvent(GameObject go) {
                Util.CallMethod(name, "OnClick", go);
            }
    
            /// <summary>
            /// 添加单击事件
            /// </summary>
            public void AddClick(GameObject go, LuaFunction luafunc) {
                if (go == null || luafunc == null) return;
                buttons.Add(go.name, luafunc);
                go.GetComponent<Button>().onClick.AddListener(
                    delegate() {
                        luafunc.Call(go);
                    }
                );
            }
    
            /// <summary>
            /// 删除单击事件
            /// </summary>
            /// <param name="go"></param>
            public void RemoveClick(GameObject go) {
                if (go == null) return;
                LuaFunction luafunc = null;
                if (buttons.TryGetValue(go.name, out luafunc)) {
                    luafunc.Dispose();
                    luafunc = null;
                    buttons.Remove(go.name);
                }
            }
    
            /// <summary>
            /// 清除单击事件
            /// </summary>
            public void ClearClick() {
                foreach (var de in buttons) {
                    if (de.Value != null) {
                        de.Value.Dispose();
                    }
                }
                buttons.Clear();
            }
    
            //-----------------------------------------------------------------
            protected void OnDestroy() {
                ClearClick();
    #if ASYNC_MODE
                string abName = name.ToLower().Replace("panel", "");
                ResManager.UnloadAssetBundle(abName + AppConst.ExtName);
    #endif
                Util.ClearMemory();
                Debug.Log("~" + name + " was destroy!");
            }
        }
    }
    Common/LuaBehaviour
    using UnityEngine;
    using System.Collections;
    using System.IO;
    using LuaInterface;
    
    namespace LuaFramework {
        /// <summary>
        /// 集成自LuaFileUtils,重写里面的ReadFile,
        /// </summary>
        public class LuaLoader : LuaFileUtils {
            private ResourceManager m_resMgr;
    
            ResourceManager resMgr {
                get { 
                    if (m_resMgr == null)
                        m_resMgr = AppFacade.Instance.GetManager<ResourceManager>(ManagerName.Resource);
                    return m_resMgr;
                }
            }
    
            // Use this for initialization
            public LuaLoader() {
                instance = this;
                beZip = AppConst.LuaBundleMode;
            }
    
            /// <summary>
            /// 添加打入Lua代码的AssetBundle
            /// </summary>
            /// <param name="bundle"></param>
            public void AddBundle(string bundleName) {
                string url = Util.DataPath + bundleName.ToLower();
                if (File.Exists(url)) {
                    var bytes = File.ReadAllBytes(url);
                    // 已注释, CreateFromMemoryImmediate从5.3开始改为LoadFromMemory,需要用的请自行取消注释~
                    // AssetBundle bundle = AssetBundle.CreateFromMemoryImmediate(bytes);
                    AssetBundle bundle = AssetBundle.LoadFromMemory(bytes);
                    if (bundle != null)
                    {
                        bundleName = bundleName.Replace("lua/", "").Replace(".unity3d", "");
                        base.AddSearchBundle(bundleName.ToLower(), bundle);
                    }
                }
            }
    
            /// <summary>
            /// 当LuaVM加载Lua文件的时候,这里就会被调用,
            /// 用户可以自定义加载行为,只要返回byte[]即可。
            /// </summary>
            /// <param name="fileName"></param>
            /// <returns></returns>
            public override byte[] ReadFile(string fileName) {
                return base.ReadFile(fileName);     
            }
        }
    }
    Common/LuaLoader
    using UnityEngine;
    using System;
    using System.Collections;
    using System.Collections.Generic;
    
    namespace LuaFramework {
        public class AppConst {
            public const bool DebugMode = false;                       //调试模式-用于内部测试
            /// <summary>
            /// 如果想删掉框架自带的例子,那这个例子模式必须要
            /// 关闭,否则会出现一些错误。
            /// </summary>
            public const bool ExampleMode = true;                       //例子模式 
    
            /// <summary>
            /// 如果开启更新模式,前提必须启动框架自带服务器端。
            /// 否则就需要自己将StreamingAssets里面的所有内容
            /// 复制到自己的Webserver上面,并修改下面的WebUrl。
            /// </summary>
            public const bool UpdateMode = false;                       //更新模式-默认关闭 
            public const bool LuaByteMode = false;                       //Lua字节码模式-默认关闭 
            public const bool LuaBundleMode = true;                    //Lua代码AssetBundle模式
    
            public const int TimerInterval = 1;
            public const int GameFrameRate = 30;                        //游戏帧频
    
            public const string AppName = "LuaFramework";               //应用程序名称
            public const string LuaTempDir = "Lua/";                    //临时目录
            public const string AppPrefix = AppName + "_";              //应用程序前缀
            public const string ExtName = ".unity3d";                   //素材扩展名
            public const string AssetDir = "StreamingAssets";           //素材目录 
            public const string WebUrl = "http://localhost:6688/";      //测试更新地址
    
            public static string UserId = string.Empty;                 //用户ID
            public static int SocketPort = 0;                           //Socket服务器端口
            public static string SocketAddress = string.Empty;          //Socket服务器地址
    
            public static string FrameworkRoot {
                get {
                    return Application.dataPath + "/" + AppName;
                }
            }
        }
    }
    ConstDefine/AppConst
    using UnityEngine;
    using System.Collections;
    
    namespace LuaFramework {
        public class ManagerName {
            public const string Lua = "LuaManager";
            public const string Game = "GameManager";
            public const string Timer = "TimeManager";
            public const string Sound = "SoundManager";
            public const string Panel = "PanelManager";
            public const string Network = "NetworkManager";
            public const string Resource = "ResourceManager";
            public const string Thread = "ThreadManager";
            public const string ObjectPool = "ObjectPoolManager";
        }
    }
    ConstDefine/ManagerName
    using UnityEngine;
    using System.Collections;
    
    public class NotiConst
    {
        /// <summary>
        /// Controller层消息通知
        /// </summary>
        public const string START_UP = "StartUp";                       //启动框架
        public const string DISPATCH_MESSAGE = "DispatchMessage";       //派发信息
    
        /// <summary>
        /// View层消息通知
        /// </summary>
        public const string UPDATE_MESSAGE = "UpdateMessage";           //更新消息
        public const string UPDATE_EXTRACT = "UpdateExtract";           //更新解包
        public const string UPDATE_DOWNLOAD = "UpdateDownload";         //更新下载
        public const string UPDATE_PROGRESS = "UpdateProgress";         //更新进度
    }
    ConstDefine/NotiConst
    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    using LuaFramework;
    
    public class SocketCommand : ControllerCommand {
    
        public override void Execute(IMessage message) {
            object data = message.Body;
            if (data == null) return;
            KeyValuePair<int, ByteBuffer> buffer = (KeyValuePair<int, ByteBuffer>)data;
            switch (buffer.Key) {
                default: Util.CallMethod("Network", "OnSocket", buffer.Key, buffer.Value); break;
            }
        }
    }
    Controller/Command/SocketCommand
    using UnityEngine;
    using System.Collections;
    using LuaFramework;
    
    public class StartUpCommand : ControllerCommand {
    
        public override void Execute(IMessage message) {
            if (!Util.CheckEnvironment()) return;
    
            GameObject gameMgr = GameObject.Find("GlobalGenerator");
            if (gameMgr != null) {
                AppView appView = gameMgr.AddComponent<AppView>();
            }
            //-----------------关联命令-----------------------
            AppFacade.Instance.RegisterCommand(NotiConst.DISPATCH_MESSAGE, typeof(SocketCommand));
    
            //-----------------初始化管理器-----------------------
            AppFacade.Instance.AddManager<LuaManager>(ManagerName.Lua);
            AppFacade.Instance.AddManager<PanelManager>(ManagerName.Panel);
            AppFacade.Instance.AddManager<SoundManager>(ManagerName.Sound);
            AppFacade.Instance.AddManager<TimerManager>(ManagerName.Timer);
            AppFacade.Instance.AddManager<NetworkManager>(ManagerName.Network);
            AppFacade.Instance.AddManager<ResourceManager>(ManagerName.Resource);
            AppFacade.Instance.AddManager<ThreadManager>(ManagerName.Thread);
            AppFacade.Instance.AddManager<ObjectPoolManager>(ManagerName.ObjectPool);
            AppFacade.Instance.AddManager<GameManager>(ManagerName.Game);
        }
    }
    Controller/Command/StartUpCommand
    using UnityEngine;
    using System.Collections;
    using LuaFramework;
    using System.Collections.Generic;
    
    public class Base : MonoBehaviour {
        private AppFacade m_Facade;
        private LuaManager m_LuaMgr;
        private ResourceManager m_ResMgr;
        private NetworkManager m_NetMgr;
        private SoundManager m_SoundMgr;
        private TimerManager m_TimerMgr;
        private ThreadManager m_ThreadMgr;
        private ObjectPoolManager m_ObjectPoolMgr;
    
        /// <summary>
        /// 注册消息
        /// </summary>
        /// <param name="view"></param>
        /// <param name="messages"></param>
        protected void RegisterMessage(IView view, List<string> messages) {
            if (messages == null || messages.Count == 0) return;
            Controller.Instance.RegisterViewCommand(view, messages.ToArray());
        }
    
        /// <summary>
        /// 移除消息
        /// </summary>
        /// <param name="view"></param>
        /// <param name="messages"></param>
        protected void RemoveMessage(IView view, List<string> messages) {
            if (messages == null || messages.Count == 0) return;
            Controller.Instance.RemoveViewCommand(view, messages.ToArray());
        }
    
        protected AppFacade facade {
            get {
                if (m_Facade == null) {
                    m_Facade = AppFacade.Instance;
                }
                return m_Facade;
            }
        }
    
        protected LuaManager LuaManager {
            get {
                if (m_LuaMgr == null) {
                    m_LuaMgr = facade.GetManager<LuaManager>(ManagerName.Lua);
                }
                return m_LuaMgr;
            }
        }
    
        protected ResourceManager ResManager {
            get {
                if (m_ResMgr == null) {
                    m_ResMgr = facade.GetManager<ResourceManager>(ManagerName.Resource);
                }
                return m_ResMgr;
            }
        }
    
        protected NetworkManager NetManager {
            get {
                if (m_NetMgr == null) {
                    m_NetMgr = facade.GetManager<NetworkManager>(ManagerName.Network);
                }
                return m_NetMgr;
            }
        }
    
        protected SoundManager SoundManager {
            get {
                if (m_SoundMgr == null) {
                    m_SoundMgr = facade.GetManager<SoundManager>(ManagerName.Sound);
                }
                return m_SoundMgr;
            }
        }
    
        protected TimerManager TimerManager {
            get {
                if (m_TimerMgr == null) {
                    m_TimerMgr = facade.GetManager<TimerManager>(ManagerName.Timer);
                }
                return m_TimerMgr;
            }
        }
    
        protected ThreadManager ThreadManager {
            get {
                if (m_ThreadMgr == null) {
                    m_ThreadMgr = facade.GetManager<ThreadManager>(ManagerName.Thread);
                }
                return m_ThreadMgr;
            }
        }
    
        protected ObjectPoolManager ObjPoolManager {
            get {
                if (m_ObjectPoolMgr == null) {
                    m_ObjectPoolMgr = facade.GetManager<ObjectPoolManager>(ManagerName.ObjectPool);
                }
                return m_ObjectPoolMgr;
            }
        }
    }
    Framework/Core/Base
    /* 
        LuaFramework Code By Jarjin lee
    */
    
    using System;
    using System.Collections.Generic;
    using UnityEngine;
    
    /// <summary>
    /// 事件命令
    /// </summary>
    public class ControllerCommand : ICommand {
        public virtual void Execute(IMessage message) {
        }
    }
    
    public class Facade {
        protected IController m_controller;
        static GameObject m_GameManager;
        static Dictionary<string, object> m_Managers = new Dictionary<string, object>();
    
        GameObject AppGameManager {
            get {
                if (m_GameManager == null) {
                    m_GameManager = GameObject.Find("GameManager");
                }
                return m_GameManager;
            }
        }
    
        protected Facade() {
            InitFramework();
        }
        protected virtual void InitFramework() {
            if (m_controller != null) return;
            m_controller = Controller.Instance;
        }
    
        public virtual void RegisterCommand(string commandName, Type commandType) {
            m_controller.RegisterCommand(commandName, commandType);
        }
    
        public virtual void RemoveCommand(string commandName) {
            m_controller.RemoveCommand(commandName);
        }
    
        public virtual bool HasCommand(string commandName) {
            return m_controller.HasCommand(commandName);
        }
    
        public void RegisterMultiCommand(Type commandType, params string[] commandNames) {
            int count = commandNames.Length;
            for (int i = 0; i < count; i++) {
                RegisterCommand(commandNames[i], commandType);
            }
        }
    
        public void RemoveMultiCommand(params string[] commandName) {
            int count = commandName.Length;
            for (int i = 0; i < count; i++) {
                RemoveCommand(commandName[i]);
            }
        }
    
        public void SendMessageCommand(string message, object body = null) {
            m_controller.ExecuteCommand(new Message(message, body));
        }
    
        /// <summary>
        /// 添加管理器
        /// </summary>
        public void AddManager(string typeName, object obj) {
            if (!m_Managers.ContainsKey(typeName)) {
                m_Managers.Add(typeName, obj);
            }
        }
    
        /// <summary>
        /// 添加Unity对象
        /// </summary>
        public T AddManager<T>(string typeName) where T : Component {
            object result = null;
            m_Managers.TryGetValue(typeName, out result);
            if (result != null) {
                return (T)result;
            }
            Component c = AppGameManager.AddComponent<T>();
            m_Managers.Add(typeName, c);
            return default(T);
        }
    
        /// <summary>
        /// 获取系统管理器
        /// </summary>
        public T GetManager<T>(string typeName) where T : class {
            if (!m_Managers.ContainsKey(typeName)) {
                return default(T);
            }
            object manager = null;
            m_Managers.TryGetValue(typeName, out manager);
            return (T)manager;
        }
    
        /// <summary>
        /// 删除管理器
        /// </summary>
        public void RemoveManager(string typeName) {
            if (!m_Managers.ContainsKey(typeName)) {
                return;
            }
            object manager = null;
            m_Managers.TryGetValue(typeName, out manager);
            Type type = manager.GetType();
            if (type.IsSubclassOf(typeof(MonoBehaviour))) {
                GameObject.Destroy((Component)manager);
            }
            m_Managers.Remove(typeName);
        }
    }
    Framework/Core/ControllerCommand, Facade
    using UnityEngine;
    using System.Collections;
    using LuaFramework;
    
    public class Manager : Base, IManager {
    
        // Use this for initialization
        void Start () {
        
        }
        
        // Update is called once per frame
        void Update () {
        
        }
    }
    Framework/Core/Manager
    /* 
     LuaFramework Code By Jarjin lee
    */
    
    using System;
    public class Message : IMessage
    {
        public Message(string name)
            : this(name, null, null)
        { }
    
        public Message(string name, object body)
            : this(name, body, null)
        { }
    
        public Message(string name, object body, string type)
        {
            m_name = name;
            m_body = body;
            m_type = type;
        }
    
        /// <summary>
        /// Get the string representation of the <c>Notification instance</c>
        /// </summary>
        /// <returns>The string representation of the <c>Notification</c> instance</returns>
        public override string ToString()
        {
            string msg = "Notification Name: " + Name;
            msg += "
    Body:" + ((Body == null) ? "null" : Body.ToString());
            msg += "
    Type:" + ((Type == null) ? "null" : Type);
            return msg;
        }
    
        /// <summary>
        /// The name of the <c>Notification</c> instance
        /// </summary>
        public virtual string Name
        {
            get { return m_name; }
        }
            
        /// <summary>
        /// The body of the <c>Notification</c> instance
        /// </summary>
        /// <remarks>This accessor is thread safe</remarks>
        public virtual object Body
        {
            get
            {
                // Setting and getting of reference types is atomic, no need to lock here
                return m_body;
            }
            set
            {
                // Setting and getting of reference types is atomic, no need to lock here
                m_body = value;
            }
        }
            
        /// <summary>
        /// The type of the <c>Notification</c> instance
        /// </summary>
        /// <remarks>This accessor is thread safe</remarks>
        public virtual string Type
        {
            get
            {
                // Setting and getting of reference types is atomic, no need to lock here
                return m_type;
            }
            set
            {
                // Setting and getting of reference types is atomic, no need to lock here
                m_type = value;
            }
        }
    
        /// <summary>
        /// The name of the notification instance 
        /// </summary>
        private string m_name;
    
        /// <summary>
        /// The type of the notification instance
        /// </summary>
        private string m_type;
    
        /// <summary>
        /// The body of the notification instance
        /// </summary>
        private object m_body;
    }
    Framework/Core/Message
    using UnityEngine;
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using LuaInterface;
    using LuaFramework;
    
    public class View : Base, IView {
        public virtual void OnMessage(IMessage message) {
        }
    }
    Framework/Core/View
    /* 
     LuaFramework Code By Jarjin lee
    */
    using System;
    
    public interface ICommand {
        void Execute(IMessage message);
    }
    Framework/Interface/ICommand
    /* 
     LuaFramework Code By Jarjin leeibution 3.0 License 
    */
    using System;
    using System.Collections.Generic;
    
    public interface IController
    {
        void RegisterCommand(string messageName, Type commandType);
        void RegisterViewCommand(IView view, string[] commandNames);
    
        void ExecuteCommand(IMessage message);
    
        void RemoveCommand(string messageName);
        void RemoveViewCommand(IView view, string[] commandNames);
    
        bool HasCommand(string messageName);
    }
    Framework/Interface/IController
    /* 
     LuaFramework Code By Jarjin leeibution 3.0 License 
    */
    
    using UnityEngine;
    using System.Collections;
    
    public interface IManager {
    }
    Framework/Interface/IManager
    /* 
     LuaFramework Code By Jarjin lee 
    */
    using System;
    
    public interface IMessage
    {
        string Name { get; }
    
        object Body { get; set; }
            
        string Type { get; set; }
    
        string ToString();
    }
    Framework/Interface/IMessage
    using System;
    
    public interface IView {
        void OnMessage(IMessage message);
    }
    Framework/Interface/IView
    using UnityEngine;
    using System;
    using System.Collections;
    using System.Collections.Generic;
    
    public class AppFacade : Facade
    {
        private static AppFacade _instance;
    
        public AppFacade() : base()
        {
        }
    
        public static AppFacade Instance
        {
            get{
                if (_instance == null) {
                    _instance = new AppFacade();
                }
                return _instance;
            }
        }
    
        override protected void InitFramework()
        {
            base.InitFramework();
            RegisterCommand(NotiConst.START_UP, typeof(StartUpCommand));
        }
    
        /// <summary>
        /// 启动框架
        /// </summary>
        public void StartUp() {
            SendMessageCommand(NotiConst.START_UP);
            RemoveMultiCommand(NotiConst.START_UP);
        }
    }
    Framework/AppFacade
    using System;
    using System.Collections;
    
    namespace LuaFramework {
        public interface ITimerBehaviour {
            void TimerUpdate();
        }
    }
    Manager/Interface
    using UnityEngine;
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using LuaInterface;
    using System.Reflection;
    using System.IO;
    
    
    namespace LuaFramework {
        public class GameManager : Manager {
            protected static bool initialize = false;
            private List<string> downloadFiles = new List<string>();
    
            /// <summary>
            /// 初始化游戏管理器
            /// </summary>
            void Awake() {
                Init();
            }
    
            /// <summary>
            /// 初始化
            /// </summary>
            void Init() {
                DontDestroyOnLoad(gameObject);  //防止销毁自己
    
                CheckExtractResource(); //释放资源
                Screen.sleepTimeout = SleepTimeout.NeverSleep;
                Application.targetFrameRate = AppConst.GameFrameRate;
            }
    
            /// <summary>
            /// 释放资源
            /// </summary>
            public void CheckExtractResource() {
                bool isExists = Directory.Exists(Util.DataPath) &&
                  Directory.Exists(Util.DataPath + "lua/") && File.Exists(Util.DataPath + "files.txt");
                if (isExists || AppConst.DebugMode) {
                    StartCoroutine(OnUpdateResource());
                    return;   //文件已经解压过了,自己可添加检查文件列表逻辑
                }
                StartCoroutine(OnExtractResource());    //启动释放协成 
            }
    
            IEnumerator OnExtractResource() {
                string dataPath = Util.DataPath;  //数据目录
                string resPath = Util.AppContentPath(); //游戏包资源目录
    
                if (Directory.Exists(dataPath)) Directory.Delete(dataPath, true);
                Directory.CreateDirectory(dataPath);
    
                string infile = resPath + "files.txt";
                string outfile = dataPath + "files.txt";
                if (File.Exists(outfile)) File.Delete(outfile);
    
                string message = "正在解包文件:>files.txt";
                Debug.Log(infile);
                Debug.Log(outfile);
                if (Application.platform == RuntimePlatform.Android) {
                    WWW www = new WWW(infile);
                    yield return www;
    
                    if (www.isDone) {
                        File.WriteAllBytes(outfile, www.bytes);
                    }
                    yield return 0;
                } else File.Copy(infile, outfile, true);
                yield return new WaitForEndOfFrame();
    
                //释放所有文件到数据目录
                string[] files = File.ReadAllLines(outfile);
                foreach (var file in files) {
                    string[] fs = file.Split('|');
                    infile = resPath + fs[0];  //
                    outfile = dataPath + fs[0];
    
                    message = "正在解包文件:>" + fs[0];
                    Debug.Log("正在解包文件:>" + infile);
                    facade.SendMessageCommand(NotiConst.UPDATE_MESSAGE, message);
    
                    string dir = Path.GetDirectoryName(outfile);
                    if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);
    
                    if (Application.platform == RuntimePlatform.Android) {
                        WWW www = new WWW(infile);
                        yield return www;
    
                        if (www.isDone) {
                            File.WriteAllBytes(outfile, www.bytes);
                        }
                        yield return 0;
                    } else {
                        if (File.Exists(outfile)) {
                            File.Delete(outfile);
                        }
                        File.Copy(infile, outfile, true);
                    }
                    yield return new WaitForEndOfFrame();
                }
                message = "解包完成!!!";
                facade.SendMessageCommand(NotiConst.UPDATE_MESSAGE, message);
                yield return new WaitForSeconds(0.1f);
    
                message = string.Empty;
                //释放完成,开始启动更新资源
                StartCoroutine(OnUpdateResource());
            }
    
            /// <summary>
            /// 启动更新下载,这里只是个思路演示,此处可启动线程下载更新
            /// </summary>
            IEnumerator OnUpdateResource() {
                if (!AppConst.UpdateMode) {
                    OnResourceInited();
                    yield break;
                }
                string dataPath = Util.DataPath;  //数据目录
                string url = AppConst.WebUrl;
                string message = string.Empty;
                string random = DateTime.Now.ToString("yyyymmddhhmmss");
                string listUrl = url + "files.txt?v=" + random;
                Debug.LogWarning("LoadUpdate---->>>" + listUrl);
    
                WWW www = new WWW(listUrl); yield return www;
                if (www.error != null) {
                    OnUpdateFailed(string.Empty);
                    yield break;
                }
                if (!Directory.Exists(dataPath)) {
                    Directory.CreateDirectory(dataPath);
                }
                File.WriteAllBytes(dataPath + "files.txt", www.bytes);
                string filesText = www.text;
                string[] files = filesText.Split('
    ');
    
                for (int i = 0; i < files.Length; i++) {
                    if (string.IsNullOrEmpty(files[i])) continue;
                    string[] keyValue = files[i].Split('|');
                    string f = keyValue[0];
                    string localfile = (dataPath + f).Trim();
                    string path = Path.GetDirectoryName(localfile);
                    if (!Directory.Exists(path)) {
                        Directory.CreateDirectory(path);
                    }
                    string fileUrl = url + f + "?v=" + random;
                    bool canUpdate = !File.Exists(localfile);
                    if (!canUpdate) {
                        string remoteMd5 = keyValue[1].Trim();
                        string localMd5 = Util.md5file(localfile);
                        canUpdate = !remoteMd5.Equals(localMd5);
                        if (canUpdate) File.Delete(localfile);
                    }
                    if (canUpdate) {   //本地缺少文件
                        Debug.Log(fileUrl);
                        message = "downloading>>" + fileUrl;
                        facade.SendMessageCommand(NotiConst.UPDATE_MESSAGE, message);
                        /*
                        www = new WWW(fileUrl); yield return www;
                        if (www.error != null) {
                            OnUpdateFailed(path);   //
                            yield break;
                        }
                        File.WriteAllBytes(localfile, www.bytes);
                         */
                        //这里都是资源文件,用线程下载
                        BeginDownload(fileUrl, localfile);
                        while (!(IsDownOK(localfile))) { yield return new WaitForEndOfFrame(); }
                    }
                }
                yield return new WaitForEndOfFrame();
    
                message = "更新完成!!";
                facade.SendMessageCommand(NotiConst.UPDATE_MESSAGE, message);
    
                OnResourceInited();
            }
    
            void OnUpdateFailed(string file) {
                string message = "更新失败!>" + file;
                facade.SendMessageCommand(NotiConst.UPDATE_MESSAGE, message);
            }
    
            /// <summary>
            /// 是否下载完成
            /// </summary>
            bool IsDownOK(string file) {
                return downloadFiles.Contains(file);
            }
    
            /// <summary>
            /// 线程下载
            /// </summary>
            void BeginDownload(string url, string file) {     //线程下载
                object[] param = new object[2] { url, file };
    
                ThreadEvent ev = new ThreadEvent();
                ev.Key = NotiConst.UPDATE_DOWNLOAD;
                ev.evParams.AddRange(param);
                ThreadManager.AddEvent(ev, OnThreadCompleted);   //线程下载
            }
    
            /// <summary>
            /// 线程完成
            /// </summary>
            /// <param name="data"></param>
            void OnThreadCompleted(NotiData data) {
                switch (data.evName) {
                    case NotiConst.UPDATE_EXTRACT:  //解压一个完成
                    //
                    break;
                    case NotiConst.UPDATE_DOWNLOAD: //下载一个完成
                    downloadFiles.Add(data.evParam.ToString());
                    break;
                }
            }
    
            /// <summary>
            /// 资源初始化结束
            /// </summary>
            public void OnResourceInited() {
    #if ASYNC_MODE
                ResManager.Initialize(AppConst.AssetDir, delegate() {
                    Debug.Log("Initialize OK!!!");
                    this.OnInitialize();
                });
    #else
                ResManager.Initialize();
                this.OnInitialize();
    #endif
            }
    
            void OnInitialize() {
                LuaManager.InitStart();
                LuaManager.DoFile("Logic/Game");         //加载游戏
                LuaManager.DoFile("Logic/Network");      //加载网络
                NetManager.OnInit();                     //初始化网络
                Util.CallMethod("Game", "OnInitOK");     //初始化完成
    
                initialize = true;
    
                //类对象池测试
                var classObjPool = ObjPoolManager.CreatePool<TestObjectClass>(OnPoolGetElement, OnPoolPushElement);
                //方法1
                //objPool.Release(new TestObjectClass("abcd", 100, 200f));
                //var testObj1 = objPool.Get();
    
                //方法2
                ObjPoolManager.Release<TestObjectClass>(new TestObjectClass("abcd", 100, 200f));
                var testObj1 = ObjPoolManager.Get<TestObjectClass>();
    
                Debugger.Log("TestObjectClass--->>>" + testObj1.ToString());
    
                //游戏对象池测试
                var prefab = Resources.Load("TestGameObjectPrefab", typeof(GameObject)) as GameObject;
                var gameObjPool = ObjPoolManager.CreatePool("TestGameObject", 5, 10, prefab);
    
                var gameObj = Instantiate(prefab) as GameObject;
                gameObj.name = "TestGameObject_01";
                gameObj.transform.localScale = Vector3.one;
                gameObj.transform.localPosition = Vector3.zero;
    
                ObjPoolManager.Release("TestGameObject", gameObj);
                var backObj = ObjPoolManager.Get("TestGameObject");
                backObj.transform.SetParent(null);
    
                Debug.Log("TestGameObject--->>>" + backObj);
            }
    
            /// <summary>
            /// 当从池子里面获取时
            /// </summary>
            /// <param name="obj"></param>
            void OnPoolGetElement(TestObjectClass obj) {
                Debug.Log("OnPoolGetElement--->>>" + obj);
            }
    
            /// <summary>
            /// 当放回池子里面时
            /// </summary>
            /// <param name="obj"></param>
            void OnPoolPushElement(TestObjectClass obj) {
                Debug.Log("OnPoolPushElement--->>>" + obj);
            }
    
            /// <summary>
            /// 析构函数
            /// </summary>
            void OnDestroy() {
                if (NetManager != null) {
                    NetManager.Unload();
                }
                if (LuaManager != null) {
                    LuaManager.Close();
                }
                Debug.Log("~GameManager was destroyed");
            }
        }
    }
    Manager/GameManager
    using UnityEngine;
    using System.Collections;
    using LuaInterface;
    
    namespace LuaFramework {
        public class LuaManager : Manager {
            private LuaState lua;
            private LuaLoader loader;
            private LuaLooper loop = null;
    
            // Use this for initialization
            void Awake() {
                loader = new LuaLoader();
                lua = new LuaState();
                this.OpenLibs();
                lua.LuaSetTop(0);
    
                LuaBinder.Bind(lua);
                DelegateFactory.Init();
                LuaCoroutine.Register(lua, this);
            }
    
            public void InitStart() {
                InitLuaPath();
                InitLuaBundle();
                this.lua.Start();    //启动LUAVM
                this.StartMain();
                this.StartLooper();
            }
    
            void StartLooper() {
                loop = gameObject.AddComponent<LuaLooper>();
                loop.luaState = lua;
            }
    
            //cjson 比较特殊,只new了一个table,没有注册库,这里注册一下
            protected void OpenCJson() {
                lua.LuaGetField(LuaIndexes.LUA_REGISTRYINDEX, "_LOADED");
                lua.OpenLibs(LuaDLL.luaopen_cjson);
                lua.LuaSetField(-2, "cjson");
    
                lua.OpenLibs(LuaDLL.luaopen_cjson_safe);
                lua.LuaSetField(-2, "cjson.safe");
            }
    
            void StartMain() {
                lua.DoFile("Main.lua");
    
                LuaFunction main = lua.GetFunction("Main");
                main.Call();
                main.Dispose();
                main = null;    
            }
            
            /// <summary>
            /// 初始化加载第三方库
            /// </summary>
            void OpenLibs() {
                lua.OpenLibs(LuaDLL.luaopen_pb);      
                lua.OpenLibs(LuaDLL.luaopen_sproto_core);
                lua.OpenLibs(LuaDLL.luaopen_protobuf_c);
                lua.OpenLibs(LuaDLL.luaopen_lpeg);
                lua.OpenLibs(LuaDLL.luaopen_bit);
                lua.OpenLibs(LuaDLL.luaopen_socket_core);
    
                this.OpenCJson();
            }
    
            /// <summary>
            /// 初始化Lua代码加载路径
            /// </summary>
            void InitLuaPath() {
                if (AppConst.DebugMode) {
                    string rootPath = AppConst.FrameworkRoot;
                    lua.AddSearchPath(rootPath + "/Lua");
                    lua.AddSearchPath(rootPath + "/ToLua/Lua");
                } else {
                    lua.AddSearchPath(Util.DataPath + "lua");
                }
            }
    
            /// <summary>
            /// 初始化LuaBundle
            /// </summary>
            void InitLuaBundle() {
                if (loader.beZip) {
                    loader.AddBundle("lua/lua.unity3d");
                    loader.AddBundle("lua/lua_math.unity3d");
                    loader.AddBundle("lua/lua_system.unity3d");
                    loader.AddBundle("lua/lua_system_reflection.unity3d");
                    loader.AddBundle("lua/lua_unityengine.unity3d");
                    loader.AddBundle("lua/lua_common.unity3d");
                    loader.AddBundle("lua/lua_logic.unity3d");
                    loader.AddBundle("lua/lua_view.unity3d");
                    loader.AddBundle("lua/lua_controller.unity3d");
                    loader.AddBundle("lua/lua_misc.unity3d");
    
                    loader.AddBundle("lua/lua_protobuf.unity3d");
                    loader.AddBundle("lua/lua_3rd_cjson.unity3d");
                    loader.AddBundle("lua/lua_3rd_luabitop.unity3d");
                    loader.AddBundle("lua/lua_3rd_pbc.unity3d");
                    loader.AddBundle("lua/lua_3rd_pblua.unity3d");
                    loader.AddBundle("lua/lua_3rd_sproto.unity3d");
                }
            }
    
            public void DoFile(string filename) {
                lua.DoFile(filename);
            }
    
            // Update is called once per frame
            public object[] CallFunction(string funcName, params object[] args) {
                LuaFunction func = lua.GetFunction(funcName);
                if (func != null) {
                    return func.LazyCall(args);
                }
                return null;
            }
    
            public void LuaGC() {
                lua.LuaGC(LuaGCOptions.LUA_GCCOLLECT);
            }
    
            public void Close() {
                loop.Destroy();
                loop = null;
    
                lua.Dispose();
                lua = null;
                loader = null;
            }
        }
    }
    Manager/LuaManager
    using UnityEngine;
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using LuaInterface;
    
    namespace LuaFramework {
        public class NetworkManager : Manager {
            private SocketClient socket;
            static readonly object m_lockObject = new object();
            static Queue<KeyValuePair<int, ByteBuffer>> mEvents = new Queue<KeyValuePair<int, ByteBuffer>>();
    
            SocketClient SocketClient {
                get { 
                    if (socket == null)
                        socket = new SocketClient();
                    return socket;                    
                }
            }
    
            void Awake() {
                Init();
            }
    
            void Init() {
                SocketClient.OnRegister();
            }
    
            public void OnInit() {
                CallMethod("Start");
            }
    
            public void Unload() {
                CallMethod("Unload");
            }
    
            /// <summary>
            /// 执行Lua方法
            /// </summary>
            public object[] CallMethod(string func, params object[] args) {
                return Util.CallMethod("Network", func, args);
            }
    
            ///------------------------------------------------------------------------------------
            public static void AddEvent(int _event, ByteBuffer data) {
                lock (m_lockObject) {
                    mEvents.Enqueue(new KeyValuePair<int, ByteBuffer>(_event, data));
                }
            }
    
            /// <summary>
            /// 交给Command,这里不想关心发给谁。
            /// </summary>
            void Update() {
                if (mEvents.Count > 0) {
                    while (mEvents.Count > 0) {
                        KeyValuePair<int, ByteBuffer> _event = mEvents.Dequeue();
                        facade.SendMessageCommand(NotiConst.DISPATCH_MESSAGE, _event);
                    }
                }
            }
    
            /// <summary>
            /// 发送链接请求
            /// </summary>
            public void SendConnect() {
                SocketClient.SendConnect();
            }
    
            /// <summary>
            /// 发送SOCKET消息
            /// </summary>
            public void SendMessage(ByteBuffer buffer) {
                SocketClient.SendMessage(buffer);
            }
    
            /// <summary>
            /// 析构函数
            /// </summary>
            new void OnDestroy() {
                SocketClient.OnRemove();
                Debug.Log("~NetworkManager was destroy");
            }
        }
    }
    Manager/NetworkManager
    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine.Events;
    
    namespace LuaFramework {
        /// <summary>
        /// 对象池管理器,分普通类对象池+资源游戏对象池
        /// </summary>
        public class ObjectPoolManager : Manager {
            private Transform m_PoolRootObject = null;
            private Dictionary<string, object> m_ObjectPools = new Dictionary<string, object>();
            private Dictionary<string, GameObjectPool> m_GameObjectPools = new Dictionary<string, GameObjectPool>();
    
            Transform PoolRootObject {
                get {
                    if (m_PoolRootObject == null) {
                        var objectPool = new GameObject("ObjectPool");
                        objectPool.transform.SetParent(transform);
                        objectPool.transform.localScale = Vector3.one;
                        objectPool.transform.localPosition = Vector3.zero;
                        m_PoolRootObject = objectPool.transform;
                    }
                    return m_PoolRootObject;
                }
            }
    
            public GameObjectPool CreatePool(string poolName, int initSize, int maxSize, GameObject prefab) {
                var pool = new GameObjectPool(poolName, prefab, initSize, maxSize, PoolRootObject);
                m_GameObjectPools[poolName] = pool;
                return pool;
            }
    
            public GameObjectPool GetPool(string poolName) {
                if (m_GameObjectPools.ContainsKey(poolName)) {
                    return m_GameObjectPools[poolName];
                }
                return null;
            }
    
            public GameObject Get(string poolName) {
                GameObject result = null;
                if (m_GameObjectPools.ContainsKey(poolName)) {
                    GameObjectPool pool = m_GameObjectPools[poolName];
                    result = pool.NextAvailableObject();
                    if (result == null) {
                        Debug.LogWarning("No object available in pool. Consider setting fixedSize to false.: " + poolName);
                    }
                } else {
                    Debug.LogError("Invalid pool name specified: " + poolName);
                }
                return result;
            }
    
            public void Release(string poolName, GameObject go) {
                if (m_GameObjectPools.ContainsKey(poolName)) {
                    GameObjectPool pool = m_GameObjectPools[poolName];
                    pool.ReturnObjectToPool(poolName, go);
                } else {
                    Debug.LogWarning("No pool available with name: " + poolName);
                }
            }
    
            ///-----------------------------------------------------------------------------------------------
    
            public ObjectPool<T> CreatePool<T>(UnityAction<T> actionOnGet, UnityAction<T> actionOnRelease) where T : class {
                var type = typeof(T);
                var pool = new ObjectPool<T>(actionOnGet, actionOnRelease);
                m_ObjectPools[type.Name] = pool;
                return pool;
            }
    
            public ObjectPool<T> GetPool<T>() where T : class {
                var type = typeof(T);
                ObjectPool<T> pool = null;
                if (m_ObjectPools.ContainsKey(type.Name)) {
                    pool = m_ObjectPools[type.Name] as ObjectPool<T>;
                }
                return pool;
            }
    
            public T Get<T>() where T : class {
                var pool = GetPool<T>();
                if (pool != null) {
                    return pool.Get();
                }
                return default(T);
            }
    
            public void Release<T>(T obj) where T : class {
                var pool = GetPool<T>();
                if (pool != null) {
                    pool.Release(obj);
                }
            }
        }
    }
    Manager/ObjectPoolManager
    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine.UI;
    using LuaInterface;
    
    namespace LuaFramework {
        public class PanelManager : Manager {
            private Transform parent;
    
            Transform Parent {
                get {
                    if (parent == null) {
                        GameObject go = GameObject.FindWithTag("GuiCamera");
                        if (go != null) parent = go.transform;
                    }
                    return parent;
                }
            }
    
            /// <summary>
            /// ������壬������Դ������
            /// </summary>
            /// <param name="type"></param>
            public void CreatePanel(string name, LuaFunction func = null) {
                string assetName = name + "Panel";
                string abName = name.ToLower() + AppConst.ExtName;
                if (Parent.Find(name) != null) return;
    
    #if ASYNC_MODE
                ResManager.LoadPrefab(abName, assetName, delegate(UnityEngine.Object[] objs) {
                    if (objs.Length == 0) return;
                    GameObject prefab = objs[0] as GameObject;
                    if (prefab == null) return;
    
                    GameObject go = Instantiate(prefab) as GameObject;
                    go.name = assetName;
                    go.layer = LayerMask.NameToLayer("Default");
                    go.transform.SetParent(Parent);
                    go.transform.localScale = Vector3.one;
                    go.transform.localPosition = Vector3.zero;
                    go.AddComponent<LuaBehaviour>();
    
                    if (func != null) func.Call(go);
                    Debug.LogWarning("CreatePanel::>> " + name + " " + prefab);
                });
    #else
                GameObject prefab = ResManager.LoadAsset<GameObject>(name, assetName);
                if (prefab == null) return;
    
                GameObject go = Instantiate(prefab) as GameObject;
                go.name = assetName;
                go.layer = LayerMask.NameToLayer("Default");
                go.transform.SetParent(Parent);
                go.transform.localScale = Vector3.one;
                go.transform.localPosition = Vector3.zero;
                go.AddComponent<LuaBehaviour>();
    
                if (func != null) func.Call(go);
                Debug.LogWarning("CreatePanel::>> " + name + " " + prefab);
    #endif
            }
    
            /// <summary>
            /// �ر����
            /// </summary>
            /// <param name="name"></param>
            public void ClosePanel(string name) {
                var panelName = name + "Panel";
                var panelObj = Parent.Find(panelName);
                if (panelObj == null) return;
                Destroy(panelObj.gameObject);
            }
        }
    }
    Manager/PanelManager
    #if ASYNC_MODE
    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    using System;
    using System.IO;
    using LuaInterface;
    using UObject = UnityEngine.Object;
    
    public class AssetBundleInfo {
        public AssetBundle m_AssetBundle;
        public int m_ReferencedCount;
    
        public AssetBundleInfo(AssetBundle assetBundle) {
            m_AssetBundle = assetBundle;
            m_ReferencedCount = 0;
        }
    }
    
    namespace LuaFramework {
    
        public class ResourceManager : Manager {
            string m_BaseDownloadingURL = "";
            string[] m_AllManifest = null;
            AssetBundleManifest m_AssetBundleManifest = null;
            Dictionary<string, string[]> m_Dependencies = new Dictionary<string, string[]>();
            Dictionary<string, AssetBundleInfo> m_LoadedAssetBundles = new Dictionary<string, AssetBundleInfo>();
            Dictionary<string, List<LoadAssetRequest>> m_LoadRequests = new Dictionary<string, List<LoadAssetRequest>>();
    
            class LoadAssetRequest {
                public Type assetType;
                public string[] assetNames;
                public LuaFunction luaFunc;
                public Action<UObject[]> sharpFunc;
            }
    
            // Load AssetBundleManifest.
            public void Initialize(string manifestName, Action initOK) {
                m_BaseDownloadingURL = Util.GetRelativePath();
                LoadAsset<AssetBundleManifest>(manifestName, new string[] { "AssetBundleManifest" }, delegate(UObject[] objs) {
                    if (objs.Length > 0) {
                        m_AssetBundleManifest = objs[0] as AssetBundleManifest;
                        m_AllManifest = m_AssetBundleManifest.GetAllAssetBundles();
                    }
                    if (initOK != null) initOK();
                });
            }
    
            public void LoadPrefab(string abName, string assetName, Action<UObject[]> func) {
                LoadAsset<GameObject>(abName, new string[] { assetName }, func);
            }
    
            public void LoadPrefab(string abName, string[] assetNames, Action<UObject[]> func) {
                LoadAsset<GameObject>(abName, assetNames, func);
            }
    
            public void LoadPrefab(string abName, string[] assetNames, LuaFunction func) {
                LoadAsset<GameObject>(abName, assetNames, null, func);
            }
    
            string GetRealAssetPath(string abName) {
                if (abName.Equals(AppConst.AssetDir)) {
                    return abName;
                }
                abName = abName.ToLower();
                if (!abName.EndsWith(AppConst.ExtName)) {
                    abName += AppConst.ExtName;
                }
                if (abName.Contains("/")) {
                    return abName;
                }
                //string[] paths = m_AssetBundleManifest.GetAllAssetBundles();  产生GC,需要缓存结果
                for (int i = 0; i < m_AllManifest.Length; i++) {
                    int index = m_AllManifest[i].LastIndexOf('/');  
                    string path = m_AllManifest[i].Remove(0, index + 1);    //字符串操作函数都会产生GC
                    if (path.Equals(abName)) {
                        return m_AllManifest[i];
                    }
                }
                Debug.LogError("GetRealAssetPath Error:>>" + abName);
                return null;
            }
    
            /// <summary>
            /// 载入素材
            /// </summary>
            void LoadAsset<T>(string abName, string[] assetNames, Action<UObject[]> action = null, LuaFunction func = null) where T : UObject {
                abName = GetRealAssetPath(abName);
    
                LoadAssetRequest request = new LoadAssetRequest();
                request.assetType = typeof(T);
                request.assetNames = assetNames;
                request.luaFunc = func;
                request.sharpFunc = action;
    
                List<LoadAssetRequest> requests = null;
                if (!m_LoadRequests.TryGetValue(abName, out requests)) {
                    requests = new List<LoadAssetRequest>();
                    requests.Add(request);
                    m_LoadRequests.Add(abName, requests);
                    StartCoroutine(OnLoadAsset<T>(abName));
                } else {
                    requests.Add(request);
                }
            }
    
            IEnumerator OnLoadAsset<T>(string abName) where T : UObject {
                Debug.Log(abName);
    
                AssetBundleInfo bundleInfo = GetLoadedAssetBundle(abName);
                if (bundleInfo == null) {
                    yield return StartCoroutine(OnLoadAssetBundle(abName, typeof(T)));
    
                    bundleInfo = GetLoadedAssetBundle(abName);
                    if (bundleInfo == null) {
                        m_LoadRequests.Remove(abName);
                        Debug.LogError("OnLoadAsset--->>>" + abName);
                        yield break;
                    }
                }
                List<LoadAssetRequest> list = null;
                if (!m_LoadRequests.TryGetValue(abName, out list)) {
                    m_LoadRequests.Remove(abName);
                    yield break;
                }
                for (int i = 0; i < list.Count; i++) {
                    string[] assetNames = list[i].assetNames;
                    List<UObject> result = new List<UObject>();
    
                    AssetBundle ab = bundleInfo.m_AssetBundle;
                    for (int j = 0; j < assetNames.Length; j++) {
                        string assetPath = assetNames[j];
                        AssetBundleRequest request = ab.LoadAssetAsync(assetPath, list[i].assetType);
                        yield return request;
                        result.Add(request.asset);
    
                        //T assetObj = ab.LoadAsset<T>(assetPath);
                        //result.Add(assetObj);
                    }
                    if (list[i].sharpFunc != null) {
                        list[i].sharpFunc(result.ToArray());
                        list[i].sharpFunc = null;
                    }
                    if (list[i].luaFunc != null) {
                        list[i].luaFunc.Call((object)result.ToArray());
                        list[i].luaFunc.Dispose();
                        list[i].luaFunc = null;
                    }
                    bundleInfo.m_ReferencedCount++;
                }
                m_LoadRequests.Remove(abName);
            }
    
            IEnumerator OnLoadAssetBundle(string abName, Type type) {
                string url = m_BaseDownloadingURL + abName;
    
                WWW download = null;
                if (type == typeof(AssetBundleManifest))
                    download = new WWW(url);
                else {
                    string[] dependencies = m_AssetBundleManifest.GetAllDependencies(abName);
                    if (dependencies.Length > 0) {
                        m_Dependencies.Add(abName, dependencies);
                        for (int i = 0; i < dependencies.Length; i++) {
                            string depName = dependencies[i];
                            AssetBundleInfo bundleInfo = null;
                            if (m_LoadedAssetBundles.TryGetValue(depName, out bundleInfo)) {
                                bundleInfo.m_ReferencedCount++;
                            } else if (!m_LoadRequests.ContainsKey(depName)) {
                                yield return StartCoroutine(OnLoadAssetBundle(depName, type));
                            }
                        }
                    }
                    download = WWW.LoadFromCacheOrDownload(url, m_AssetBundleManifest.GetAssetBundleHash(abName), 0);
                }
                yield return download;
    
                AssetBundle assetObj = download.assetBundle;
                if (assetObj != null) {
                    m_LoadedAssetBundles.Add(abName, new AssetBundleInfo(assetObj));
                }
            }
    
            AssetBundleInfo GetLoadedAssetBundle(string abName) {
                AssetBundleInfo bundle = null;
                m_LoadedAssetBundles.TryGetValue(abName, out bundle);
                if (bundle == null) return null;
    
                // No dependencies are recorded, only the bundle itself is required.
                string[] dependencies = null;
                if (!m_Dependencies.TryGetValue(abName, out dependencies))
                    return bundle;
    
                // Make sure all dependencies are loaded
                foreach (var dependency in dependencies) {
                    AssetBundleInfo dependentBundle;
                    m_LoadedAssetBundles.TryGetValue(dependency, out dependentBundle);
                    if (dependentBundle == null) return null;
                }
                return bundle;
            }
    
            /// <summary>
            /// 此函数交给外部卸载专用,自己调整是否需要彻底清除AB
            /// </summary>
            /// <param name="abName"></param>
            /// <param name="isThorough"></param>
            public void UnloadAssetBundle(string abName, bool isThorough = false) {
                abName = GetRealAssetPath(abName);
                Debug.Log(m_LoadedAssetBundles.Count + " assetbundle(s) in memory before unloading " + abName);
                UnloadAssetBundleInternal(abName, isThorough);
                UnloadDependencies(abName, isThorough);
                Debug.Log(m_LoadedAssetBundles.Count + " assetbundle(s) in memory after unloading " + abName);
            }
    
            void UnloadDependencies(string abName, bool isThorough) {
                string[] dependencies = null;
                if (!m_Dependencies.TryGetValue(abName, out dependencies))
                    return;
    
                // Loop dependencies.
                foreach (var dependency in dependencies) {
                    UnloadAssetBundleInternal(dependency, isThorough);
                }
                m_Dependencies.Remove(abName);
            }
    
            void UnloadAssetBundleInternal(string abName, bool isThorough) {
                AssetBundleInfo bundle = GetLoadedAssetBundle(abName);
                if (bundle == null) return;
    
                if (--bundle.m_ReferencedCount <= 0) {
                    if (m_LoadRequests.ContainsKey(abName)) {
                        return;     //如果当前AB处于Async Loading过程中,卸载会崩溃,只减去引用计数即可
                    }
                    bundle.m_AssetBundle.Unload(isThorough);
                    m_LoadedAssetBundles.Remove(abName);
                    Debug.Log(abName + " has been unloaded successfully");
                }
            }
        }
    }
    #else
    
    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    using System.IO;
    using LuaFramework;
    using LuaInterface;
    using UObject = UnityEngine.Object;
    
    namespace LuaFramework {
        public class ResourceManager : Manager {
            private string[] m_Variants = { };
            private AssetBundleManifest manifest;
            private AssetBundle shared, assetbundle;
            private Dictionary<string, AssetBundle> bundles;
    
            void Awake() {
            }
    
            /// <summary>
            /// 初始化
            /// </summary>
            public void Initialize() {
                byte[] stream = null;
                string uri = string.Empty;
                bundles = new Dictionary<string, AssetBundle>();
                uri = Util.DataPath + AppConst.AssetDir;
                if (!File.Exists(uri)) return;
                stream = File.ReadAllBytes(uri);
                assetbundle = AssetBundle.CreateFromMemoryImmediate(stream);
                manifest = assetbundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
            }
    
            /// <summary>
            /// 载入素材
            /// </summary>
            public T LoadAsset<T>(string abname, string assetname) where T : UnityEngine.Object {
                abname = abname.ToLower();
                AssetBundle bundle = LoadAssetBundle(abname);
                return bundle.LoadAsset<T>(assetname);
            }
    
            public void LoadPrefab(string abName, string[] assetNames, LuaFunction func) {
                abName = abName.ToLower();
                List<UObject> result = new List<UObject>();
                for (int i = 0; i < assetNames.Length; i++) {
                    UObject go = LoadAsset<UObject>(abName, assetNames[i]);
                    if (go != null) result.Add(go);
                }
                if (func != null) func.Call((object)result.ToArray());
            }
    
            /// <summary>
            /// 载入AssetBundle
            /// </summary>
            /// <param name="abname"></param>
            /// <returns></returns>
            public AssetBundle LoadAssetBundle(string abname) {
                if (!abname.EndsWith(AppConst.ExtName)) {
                    abname += AppConst.ExtName;
                }
                AssetBundle bundle = null;
                if (!bundles.ContainsKey(abname)) {
                    byte[] stream = null;
                    string uri = Util.DataPath + abname;
                    Debug.LogWarning("LoadFile::>> " + uri);
                    LoadDependencies(abname);
    
                    stream = File.ReadAllBytes(uri);
                    bundle = AssetBundle.CreateFromMemoryImmediate(stream); //关联数据的素材绑定
                    bundles.Add(abname, bundle);
                } else {
                    bundles.TryGetValue(abname, out bundle);
                }
                return bundle;
            }
    
            /// <summary>
            /// 载入依赖
            /// </summary>
            /// <param name="name"></param>
            void LoadDependencies(string name) {
                if (manifest == null) {
                    Debug.LogError("Please initialize AssetBundleManifest by calling AssetBundleManager.Initialize()");
                    return;
                }
                // Get dependecies from the AssetBundleManifest object..
                string[] dependencies = manifest.GetAllDependencies(name);
                if (dependencies.Length == 0) return;
    
                for (int i = 0; i < dependencies.Length; i++)
                    dependencies[i] = RemapVariantName(dependencies[i]);
    
                // Record and load all dependencies.
                for (int i = 0; i < dependencies.Length; i++) {
                    LoadAssetBundle(dependencies[i]);
                }
            }
    
            // Remaps the asset bundle name to the best fitting asset bundle variant.
            string RemapVariantName(string assetBundleName) {
                string[] bundlesWithVariant = manifest.GetAllAssetBundlesWithVariant();
    
                // If the asset bundle doesn't have variant, simply return.
                if (System.Array.IndexOf(bundlesWithVariant, assetBundleName) < 0)
                    return assetBundleName;
    
                string[] split = assetBundleName.Split('.');
    
                int bestFit = int.MaxValue;
                int bestFitIndex = -1;
                // Loop all the assetBundles with variant to find the best fit variant assetBundle.
                for (int i = 0; i < bundlesWithVariant.Length; i++) {
                    string[] curSplit = bundlesWithVariant[i].Split('.');
                    if (curSplit[0] != split[0])
                        continue;
    
                    int found = System.Array.IndexOf(m_Variants, curSplit[1]);
                    if (found != -1 && found < bestFit) {
                        bestFit = found;
                        bestFitIndex = i;
                    }
                }
                if (bestFitIndex != -1)
                    return bundlesWithVariant[bestFitIndex];
                else
                    return assetBundleName;
            }
    
            /// <summary>
            /// 销毁资源
            /// </summary>
            void OnDestroy() {
                if (shared != null) shared.Unload(true);
                if (manifest != null) manifest = null;
                Debug.Log("~ResourceManager was destroy!");
            }
        }
    }
    #endif
    Manager/ResourceManager, AssetBundleInfo
    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    
    namespace LuaFramework {
        public class SoundManager : Manager {
            private AudioSource audio;
            private Hashtable sounds = new Hashtable();
    
            void Start() {
                audio = GetComponent<AudioSource>();
            }
    
            /// <summary>
            /// 添加一个声音
            /// </summary>
            void Add(string key, AudioClip value) {
                if (sounds[key] != null || value == null) return;
                sounds.Add(key, value);
            }
    
            /// <summary>
            /// 获取一个声音
            /// </summary>
            AudioClip Get(string key) {
                if (sounds[key] == null) return null;
                return sounds[key] as AudioClip;
            }
    
            /// <summary>
            /// 载入一个音频
            /// </summary>
            public AudioClip LoadAudioClip(string path) {
                AudioClip ac = Get(path);
                if (ac == null) {
                    ac = (AudioClip)Resources.Load(path, typeof(AudioClip));
                    Add(path, ac);
                }
                return ac;
            }
    
            /// <summary>
            /// 是否播放背景音乐,默认是1:播放
            /// </summary>
            /// <returns></returns>
            public bool CanPlayBackSound() {
                string key = AppConst.AppPrefix + "BackSound";
                int i = PlayerPrefs.GetInt(key, 1);
                return i == 1;
            }
    
            /// <summary>
            /// 播放背景音乐
            /// </summary>
            /// <param name="canPlay"></param>
            public void PlayBacksound(string name, bool canPlay) {
                if (audio.clip != null) {
                    if (name.IndexOf(audio.clip.name) > -1) {
                        if (!canPlay) {
                            audio.Stop();
                            audio.clip = null;
                            Util.ClearMemory();
                        }
                        return;
                    }
                }
                if (canPlay) {
                    audio.loop = true;
                    audio.clip = LoadAudioClip(name);
                    audio.Play();
                } else {
                    audio.Stop();
                    audio.clip = null;
                    Util.ClearMemory();
                }
            }
    
            /// <summary>
            /// 是否播放音效,默认是1:播放
            /// </summary>
            /// <returns></returns>
            public bool CanPlaySoundEffect() {
                string key = AppConst.AppPrefix + "SoundEffect";
                int i = PlayerPrefs.GetInt(key, 1);
                return i == 1;
            }
    
            /// <summary>
            /// 播放音频剪辑
            /// </summary>
            /// <param name="clip"></param>
            /// <param name="position"></param>
            public void Play(AudioClip clip, Vector3 position) {
                if (!CanPlaySoundEffect()) return;
                AudioSource.PlayClipAtPoint(clip, position); 
            }
        }
    }
    Manager/SoundManager
    using System.Collections;
    using System.Threading;
    using System.Collections.Generic;
    using System.IO;
    using System.Diagnostics;
    using System.Net;
    using System;
    
    public class ThreadEvent {
        public string Key;
        public List<object> evParams = new List<object>();
    }
    
    public class NotiData {
        public string evName;
        public object evParam;
    
        public NotiData(string name, object param) {
            this.evName = name;
            this.evParam = param;
        }
    }
    
    namespace LuaFramework {
        /// <summary>
        /// 当前线程管理器,同时只能做一个任务
        /// </summary>
        public class ThreadManager : Manager {
            private Thread thread;
            private Action<NotiData> func;
            private Stopwatch sw = new Stopwatch();
            private string currDownFile = string.Empty;
    
            static readonly object m_lockObject = new object();
            static Queue<ThreadEvent> events = new Queue<ThreadEvent>();
    
            delegate void ThreadSyncEvent(NotiData data);
            private ThreadSyncEvent m_SyncEvent;
    
            void Awake() {
                m_SyncEvent = OnSyncEvent;
                thread = new Thread(OnUpdate);
            }
    
            // Use this for initialization
            void Start() {
                thread.Start();
            }
    
            /// <summary>
            /// 添加到事件队列
            /// </summary>
            public void AddEvent(ThreadEvent ev, Action<NotiData> func) {
                lock (m_lockObject) {
                    this.func = func;
                    events.Enqueue(ev);
                }
            }
    
            /// <summary>
            /// 通知事件
            /// </summary>
            /// <param name="state"></param>
            private void OnSyncEvent(NotiData data) {
                if (this.func != null) func(data);  //回调逻辑层
                facade.SendMessageCommand(data.evName, data.evParam); //通知View层
            }
    
            // Update is called once per frame
            void OnUpdate() {
                while (true) {
                    lock (m_lockObject) {
                        if (events.Count > 0) {
                            ThreadEvent e = events.Dequeue();
                            try {
                                switch (e.Key) {
                                    case NotiConst.UPDATE_EXTRACT: {     //解压文件
                                        OnExtractFile(e.evParams);
                                    }
                                    break;
                                    case NotiConst.UPDATE_DOWNLOAD: {    //下载文件
                                        OnDownloadFile(e.evParams);
                                    }
                                    break;
                                }
                            } catch (System.Exception ex) {
                                UnityEngine.Debug.LogError(ex.Message);
                            }
                        }
                    }
                    Thread.Sleep(1);
                }
            }
    
            /// <summary>
            /// 下载文件
            /// </summary>
            void OnDownloadFile(List<object> evParams) {
                string url = evParams[0].ToString();    
                currDownFile = evParams[1].ToString();
    
                using (WebClient client = new WebClient()) {
                    sw.Start();
                    client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgressChanged);
                    client.DownloadFileAsync(new System.Uri(url), currDownFile);
                }
            }
    
            private void ProgressChanged(object sender, DownloadProgressChangedEventArgs e) {
                //UnityEngine.Debug.Log(e.ProgressPercentage);
                /*
                UnityEngine.Debug.Log(string.Format("{0} MB's / {1} MB's",
                    (e.BytesReceived / 1024d / 1024d).ToString("0.00"),
                    (e.TotalBytesToReceive / 1024d / 1024d).ToString("0.00")));
                */
                //float value = (float)e.ProgressPercentage / 100f;
    
                string value = string.Format("{0} kb/s", (e.BytesReceived / 1024d / sw.Elapsed.TotalSeconds).ToString("0.00"));
                NotiData data = new NotiData(NotiConst.UPDATE_PROGRESS, value);
                if (m_SyncEvent != null) m_SyncEvent(data);
    
                if (e.ProgressPercentage == 100 && e.BytesReceived == e.TotalBytesToReceive) {
                    sw.Reset();
    
                    data = new NotiData(NotiConst.UPDATE_DOWNLOAD, currDownFile);
                    if (m_SyncEvent != null) m_SyncEvent(data);
                }
            }
    
            /// <summary>
            /// 调用方法
            /// </summary>
            void OnExtractFile(List<object> evParams) {
                UnityEngine.Debug.LogWarning("Thread evParams: >>" + evParams.Count);
    
                ///------------------通知更新面板解压完成--------------------
                NotiData data = new NotiData(NotiConst.UPDATE_DOWNLOAD, null);
                if (m_SyncEvent != null) m_SyncEvent(data);
            }
    
            /// <summary>
            /// 应用程序退出
            /// </summary>
            void OnDestroy() {
                thread.Abort();
            }
        }
    }
    Manager/ThreadManager, ThreadEvent, NotiData
    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    
    namespace LuaFramework {
        public class TimerInfo {
            public long tick;
            public bool stop;
            public bool delete;
            public Object target;
            public string className;
    
            public TimerInfo(string className, Object target) {
                this.className = className;
                this.target = target;
                delete = false;
            }
        }
    
    
        public class TimerManager : Manager {
            private float interval = 0;
            private List<TimerInfo> objects = new List<TimerInfo>();
    
            public float Interval {
                get { return interval; }
                set { interval = value; }
            }
    
            // Use this for initialization
            void Start() {
                StartTimer(AppConst.TimerInterval);
            }
    
            /// <summary>
            /// 启动计时器
            /// </summary>
            /// <param name="interval"></param>
            public void StartTimer(float value) {
                interval = value;
                InvokeRepeating("Run", 0, interval);
            }
    
            /// <summary>
            /// 停止计时器
            /// </summary>
            public void StopTimer() {
                CancelInvoke("Run");
            }
    
            /// <summary>
            /// 添加计时器事件
            /// </summary>
            /// <param name="name"></param>
            /// <param name="o"></param>
            public void AddTimerEvent(TimerInfo info) {
                if (!objects.Contains(info)) {
                    objects.Add(info);
                }
            }
    
            /// <summary>
            /// 删除计时器事件
            /// </summary>
            /// <param name="name"></param>
            public void RemoveTimerEvent(TimerInfo info) {
                if (objects.Contains(info) && info != null) {
                    info.delete = true;
                }
            }
    
            /// <summary>
            /// 停止计时器事件
            /// </summary>
            /// <param name="info"></param>
            public void StopTimerEvent(TimerInfo info) {
                if (objects.Contains(info) && info != null) {
                    info.stop = true;
                }
            }
    
            /// <summary>
            /// 继续计时器事件
            /// </summary>
            /// <param name="info"></param>
            public void ResumeTimerEvent(TimerInfo info) {
                if (objects.Contains(info) && info != null) {
                    info.delete = false;
                }
            }
    
            /// <summary>
            /// 计时器运行
            /// </summary>
            void Run() {
                if (objects.Count == 0) return;
                for (int i = 0; i < objects.Count; i++) {
                    TimerInfo o = objects[i];
                    if (o.delete || o.stop) { continue; }
                    ITimerBehaviour timer = o.target as ITimerBehaviour;
                    timer.TimerUpdate();
                    o.tick++;
                }
                /////////////////////////清除标记为删除的事件///////////////////////////
                for (int i = objects.Count - 1; i >= 0; i--) {
                    if (objects[i].delete) { objects.Remove(objects[i]); }
                }
            }
        }
    }
    Manager/TimerManager, TimerInfo
    using UnityEngine;
    using System.Collections;
    using System.IO;
    using System.Text;
    using System;
    using LuaInterface;
    
    namespace LuaFramework {
        public class ByteBuffer {
            MemoryStream stream = null;
            BinaryWriter writer = null;
            BinaryReader reader = null;
    
            public ByteBuffer() {
                stream = new MemoryStream();
                writer = new BinaryWriter(stream);
            }
    
            public ByteBuffer(byte[] data) {
                if (data != null) {
                    stream = new MemoryStream(data);
                    reader = new BinaryReader(stream);
                } else {
                    stream = new MemoryStream();
                    writer = new BinaryWriter(stream);
                }
            }
    
            public void Close() {
                if (writer != null) writer.Close();
                if (reader != null) reader.Close();
    
                stream.Close();
                writer = null;
                reader = null;
                stream = null;
            }
    
            public void WriteByte(byte v) {
                writer.Write(v);
            }
    
            public void WriteInt(int v) {
                writer.Write((int)v);
            }
    
            public void WriteShort(ushort v) {
                writer.Write((ushort)v);
            }
    
            public void WriteLong(long v) {
                writer.Write((long)v);
            }
    
            public void WriteFloat(float v) {
                byte[] temp = BitConverter.GetBytes(v);
                Array.Reverse(temp);
                writer.Write(BitConverter.ToSingle(temp, 0));
            }
    
            public void WriteDouble(double v) {
                byte[] temp = BitConverter.GetBytes(v);
                Array.Reverse(temp);
                writer.Write(BitConverter.ToDouble(temp, 0));
            }
    
            public void WriteString(string v) {
                byte[] bytes = Encoding.UTF8.GetBytes(v);
                writer.Write((ushort)bytes.Length);
                writer.Write(bytes);
            }
    
            public void WriteBytes(byte[] v) {
                writer.Write((int)v.Length);
                writer.Write(v);
            }
    
            public void WriteBuffer(LuaByteBuffer strBuffer) {
                WriteBytes(strBuffer.buffer);
            }
    
            public byte ReadByte() {
                return reader.ReadByte();
            }
    
            public int ReadInt() {
                return (int)reader.ReadInt32();
            }
    
            public ushort ReadShort() {
                return (ushort)reader.ReadInt16();
            }
    
            public long ReadLong() {
                return (long)reader.ReadInt64();
            }
    
            public float ReadFloat() {
                byte[] temp = BitConverter.GetBytes(reader.ReadSingle());
                Array.Reverse(temp);
                return BitConverter.ToSingle(temp, 0);
            }
    
            public double ReadDouble() {
                byte[] temp = BitConverter.GetBytes(reader.ReadDouble());
                Array.Reverse(temp);
                return BitConverter.ToDouble(temp, 0);
            }
    
            public string ReadString() {
                ushort len = ReadShort();
                byte[] buffer = new byte[len];
                buffer = reader.ReadBytes(len);
                return Encoding.UTF8.GetString(buffer);
            }
    
            public byte[] ReadBytes() {
                int len = ReadInt();
                return reader.ReadBytes(len);
            }
    
            public LuaByteBuffer ReadBuffer() {
                byte[] bytes = ReadBytes();
                return new LuaByteBuffer(bytes);
            }
    
            public byte[] ToBytes() {
                writer.Flush();
                return stream.ToArray();
            }
    
            public void Flush() {
                writer.Flush();
            }
        }
    }
    Network/ByteBuffer
    /*
    *  Copyright (c) 2008 Jonathan Wagner
    *
    * 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 LuaFramework {
        public class Converter {
            public static Int32 GetBigEndian(Int32 value) {
                if (BitConverter.IsLittleEndian) {
                    return swapByteOrder(value);
                } else {
                    return value;
                }
            }
    
            public static UInt16 GetBigEndian(UInt16 value) {
                if (BitConverter.IsLittleEndian) {
                    return swapByteOrder(value);
                } else {
                    return value;
                }
            }
    
            public static UInt32 GetBigEndian(UInt32 value) {
                if (BitConverter.IsLittleEndian) {
                    return swapByteOrder(value);
                } else {
                    return value;
                }
            }
    
            public static Int64 GetBigEndian(Int64 value) {
                if (BitConverter.IsLittleEndian) {
                    return swapByteOrder(value);
                } else {
                    return value;
                }
            }
    
            public static Double GetBigEndian(Double value) {
                if (BitConverter.IsLittleEndian) {
                    return swapByteOrder(value);
                } else {
                    return value;
                }
            }
    
            public static float GetBigEndian(float value) {
                if (BitConverter.IsLittleEndian) {
                    return swapByteOrder((int)value);
    
                } else {
                    return value;
                }
            }
    
            public static Int32 GetLittleEndian(Int32 value) {
                if (BitConverter.IsLittleEndian) {
                    return value;
                } else {
                    return swapByteOrder(value);
                }
            }
    
            public static UInt32 GetLittleEndian(UInt32 value) {
                if (BitConverter.IsLittleEndian) {
                    return value;
                } else {
                    return swapByteOrder(value);
                }
            }
    
            public static UInt16 GetLittleEndian(UInt16 value) {
                if (BitConverter.IsLittleEndian) {
                    return value;
                } else {
                    return swapByteOrder(value);
                }
            }
    
            public static Double GetLittleEndian(Double value) {
                if (BitConverter.IsLittleEndian) {
                    return value;
                } else {
                    return swapByteOrder(value);
                }
            }
    
            private static Int32 swapByteOrder(Int32 value) {
                Int32 swap = (Int32)((0x000000FF) & (value >> 24)
                    | (0x0000FF00) & (value >> 8)
                    | (0x00FF0000) & (value << 8)
                    | (0xFF000000) & (value << 24));
                return swap;
            }
    
            private static Int64 swapByteOrder(Int64 value) {
                UInt64 uvalue = (UInt64)value;
                UInt64 swap = ((0x00000000000000FF) & (uvalue >> 56)
                | (0x000000000000FF00) & (uvalue >> 40)
                | (0x0000000000FF0000) & (uvalue >> 24)
                | (0x00000000FF000000) & (uvalue >> 8)
                | (0x000000FF00000000) & (uvalue << 8)
                | (0x0000FF0000000000) & (uvalue << 24)
                | (0x00FF000000000000) & (uvalue << 40)
                | (0xFF00000000000000) & (uvalue << 56));
    
                return (Int64)swap;
            }
    
            private static UInt16 swapByteOrder(UInt16 value) {
                return (UInt16)((0x00FF & (value >> 8))
                    | (0xFF00 & (value << 8)));
            }
    
            private static UInt32 swapByteOrder(UInt32 value) {
                UInt32 swap = ((0x000000FF) & (value >> 24)
                    | (0x0000FF00) & (value >> 8)
                    | (0x00FF0000) & (value << 8)
                    | (0xFF000000) & (value << 24));
                return swap;
            }
    
            private static Double swapByteOrder(Double value) {
                Byte[] buffer = BitConverter.GetBytes(value);
                Array.Reverse(buffer, 0, buffer.Length);
                return BitConverter.ToDouble(buffer, 0);
            }
        }
    }
    Network/Converter
    namespace LuaFramework {
        public class Protocal {
            ///BUILD TABLE
            public const int Connect = 101;     //连接服务器
            public const int Exception = 102;     //异常掉线
            public const int Disconnect = 103;     //正常断线   
        }
    }
    Network/Protocal
    using UnityEngine;
    using System;
    using System.IO;
    using System.Net;
    using System.Net.Sockets;
    using System.Collections;
    using System.Collections.Generic;
    using LuaFramework;
    
    public enum DisType {
        Exception,
        Disconnect,
    }
    
    public class SocketClient {
        private TcpClient client = null;
        private NetworkStream outStream = null;
        private MemoryStream memStream;
        private BinaryReader reader;
    
        private const int MAX_READ = 8192;
        private byte[] byteBuffer = new byte[MAX_READ];
        public static bool loggedIn = false;
    
        // Use this for initialization
        public SocketClient() {
        }
    
        /// <summary>
        /// 注册代理
        /// </summary>
        public void OnRegister() {
            memStream = new MemoryStream();
            reader = new BinaryReader(memStream);
        }
    
        /// <summary>
        /// 移除代理
        /// </summary>
        public void OnRemove() {
            this.Close();
            reader.Close();
            memStream.Close();
        }
    
        /// <summary>
        /// 连接服务器
        /// </summary>
        void ConnectServer(string host, int port) {
            client = null;
            try {
                IPAddress[] address = Dns.GetHostAddresses(host);
                if (address.Length == 0) {
                    Debug.LogError("host invalid");
                    return;
                }
                if (address[0].AddressFamily == AddressFamily.InterNetworkV6) {
                    client = new TcpClient(AddressFamily.InterNetworkV6);
                }
                else {
                    client = new TcpClient(AddressFamily.InterNetwork);
                }
                client.SendTimeout = 1000;
                client.ReceiveTimeout = 1000;
                client.NoDelay = true;
                client.BeginConnect(host, port, new AsyncCallback(OnConnect), null);
            } catch (Exception e) {
                Close(); Debug.LogError(e.Message);
            }
        }
    
        /// <summary>
        /// 连接上服务器
        /// </summary>
        void OnConnect(IAsyncResult asr) {
            outStream = client.GetStream();
            client.GetStream().BeginRead(byteBuffer, 0, MAX_READ, new AsyncCallback(OnRead), null);
            NetworkManager.AddEvent(Protocal.Connect, new ByteBuffer());
        }
    
        /// <summary>
        /// 写数据
        /// </summary>
        void WriteMessage(byte[] message) {
            MemoryStream ms = null;
            using (ms = new MemoryStream()) {
                ms.Position = 0;
                BinaryWriter writer = new BinaryWriter(ms);
                ushort msglen = (ushort)message.Length;
                writer.Write(msglen);
                writer.Write(message);
                writer.Flush();
                if (client != null && client.Connected) {
                    //NetworkStream stream = client.GetStream();
                    byte[] payload = ms.ToArray();
                    outStream.BeginWrite(payload, 0, payload.Length, new AsyncCallback(OnWrite), null);
                } else {
                    Debug.LogError("client.connected----->>false");
                }
            }
        }
    
        /// <summary>
        /// 读取消息
        /// </summary>
        void OnRead(IAsyncResult asr) {
            int bytesRead = 0;
            try {
                lock (client.GetStream()) {         //读取字节流到缓冲区
                    bytesRead = client.GetStream().EndRead(asr);
                }
                if (bytesRead < 1) {                //包尺寸有问题,断线处理
                    OnDisconnected(DisType.Disconnect, "bytesRead < 1");
                    return;
                }
                OnReceive(byteBuffer, bytesRead);   //分析数据包内容,抛给逻辑层
                lock (client.GetStream()) {         //分析完,再次监听服务器发过来的新消息
                    Array.Clear(byteBuffer, 0, byteBuffer.Length);   //清空数组
                    client.GetStream().BeginRead(byteBuffer, 0, MAX_READ, new AsyncCallback(OnRead), null);
                }
            } catch (Exception ex) {
                //PrintBytes();
                OnDisconnected(DisType.Exception, ex.Message);
            }
        }
    
        /// <summary>
        /// 丢失链接
        /// </summary>
        void OnDisconnected(DisType dis, string msg) {
            Close();   //关掉客户端链接
            int protocal = dis == DisType.Exception ?
            Protocal.Exception : Protocal.Disconnect;
    
            ByteBuffer buffer = new ByteBuffer();
            buffer.WriteShort((ushort)protocal);
            NetworkManager.AddEvent(protocal, buffer);
            Debug.LogError("Connection was closed by the server:>" + msg + " Distype:>" + dis);
        }
    
        /// <summary>
        /// 打印字节
        /// </summary>
        /// <param name="bytes"></param>
        void PrintBytes() {
            string returnStr = string.Empty;
            for (int i = 0; i < byteBuffer.Length; i++) {
                returnStr += byteBuffer[i].ToString("X2");
            }
            Debug.LogError(returnStr);
        }
    
        /// <summary>
        /// 向链接写入数据流
        /// </summary>
        void OnWrite(IAsyncResult r) {
            try {
                outStream.EndWrite(r);
            } catch (Exception ex) {
                Debug.LogError("OnWrite--->>>" + ex.Message);
            }
        }
    
        /// <summary>
        /// 接收到消息
        /// </summary>
        void OnReceive(byte[] bytes, int length) {
            memStream.Seek(0, SeekOrigin.End);
            memStream.Write(bytes, 0, length);
            //Reset to beginning
            memStream.Seek(0, SeekOrigin.Begin);
            while (RemainingBytes() > 2) {
                ushort messageLen = reader.ReadUInt16();
                if (RemainingBytes() >= messageLen) {
                    MemoryStream ms = new MemoryStream();
                    BinaryWriter writer = new BinaryWriter(ms);
                    writer.Write(reader.ReadBytes(messageLen));
                    ms.Seek(0, SeekOrigin.Begin);
                    OnReceivedMessage(ms);
                } else {
                    //Back up the position two bytes
                    memStream.Position = memStream.Position - 2;
                    break;
                }
            }
            //Create a new stream with any leftover bytes
            byte[] leftover = reader.ReadBytes((int)RemainingBytes());
            memStream.SetLength(0);     //Clear
            memStream.Write(leftover, 0, leftover.Length);
        }
    
        /// <summary>
        /// 剩余的字节
        /// </summary>
        private long RemainingBytes() {
            return memStream.Length - memStream.Position;
        }
    
        /// <summary>
        /// 接收到消息
        /// </summary>
        /// <param name="ms"></param>
        void OnReceivedMessage(MemoryStream ms) {
            BinaryReader r = new BinaryReader(ms);
            byte[] message = r.ReadBytes((int)(ms.Length - ms.Position));
            //int msglen = message.Length;
    
            ByteBuffer buffer = new ByteBuffer(message);
            int mainId = buffer.ReadShort();
            NetworkManager.AddEvent(mainId, buffer);
        }
    
    
        /// <summary>
        /// 会话发送
        /// </summary>
        void SessionSend(byte[] bytes) {
            WriteMessage(bytes);
        }
    
        /// <summary>
        /// 关闭链接
        /// </summary>
        public void Close() {
            if (client != null) {
                if (client.Connected) client.Close();
                client = null;
            }
            loggedIn = false;
        }
    
        /// <summary>
        /// 发送连接请求
        /// </summary>
        public void SendConnect() {
            ConnectServer(AppConst.SocketAddress, AppConst.SocketPort);
        }
    
        /// <summary>
        /// 发送消息
        /// </summary>
        public void SendMessage(ByteBuffer buffer) {
            SessionSend(buffer.ToBytes());
            buffer.Close();
        }
    }
    Network/SocketClient, DisType
    using UnityEngine;
    using System;
    using System.Collections;
    using System.Collections.Generic;
    
    namespace LuaFramework {
    
        [Serializable]
        public class PoolInfo {
            public string poolName;
            public GameObject prefab;
            public int poolSize;
            public bool fixedSize;
        }
    
        public class GameObjectPool {
            private int maxSize;
            private int poolSize;
            private string poolName;
            private Transform poolRoot;
            private GameObject poolObjectPrefab;
            private Stack<GameObject> availableObjStack = new Stack<GameObject>();
    
            public GameObjectPool(string poolName, GameObject poolObjectPrefab, int initCount, int maxSize, Transform pool) {
                this.poolName = poolName;
                this.poolSize = initCount;
                this.maxSize = maxSize;
                this.poolRoot = pool;
                this.poolObjectPrefab = poolObjectPrefab;
    
                //populate the pool
                for(int index = 0; index < initCount; index++) {
                    AddObjectToPool(NewObjectInstance());
                }
            }
    
            //o(1)
            private void AddObjectToPool(GameObject go) {
                //add to pool
                go.SetActive(false);
                availableObjStack.Push(go);
                go.transform.SetParent(poolRoot, false);
            }
    
            private GameObject NewObjectInstance() {
                return GameObject.Instantiate(poolObjectPrefab) as GameObject;
            }
    
            public GameObject NextAvailableObject() {
                GameObject go = null;
                if(availableObjStack.Count > 0) {
                    go = availableObjStack.Pop();
                } else {
                    Debug.LogWarning("No object available & cannot grow pool: " + poolName);
                }
                go.SetActive(true);
                return go;
            } 
            
            //o(1)
            public void ReturnObjectToPool(string pool, GameObject po) {
                if (poolName.Equals(pool)) {
                    AddObjectToPool(po);
                } else {
                    Debug.LogError(string.Format("Trying to add object to incorrect pool {0} ", poolName));
                }
            }
        }
    }
    ObjectPool/GameObjectPool, PoolInfo
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.Events;
    
    namespace LuaFramework
    {
        public class ObjectPool<T> where T : class
        {
            private readonly Stack<T> m_Stack = new Stack<T>();
            private readonly UnityAction<T> m_ActionOnGet;
            private readonly UnityAction<T> m_ActionOnRelease;
    
            public int countAll { get; private set; }
            public int countActive { get { return countAll - countInactive; } }
            public int countInactive { get { return m_Stack.Count; } }
    
            public ObjectPool(UnityAction<T> actionOnGet, UnityAction<T> actionOnRelease)
            {
                m_ActionOnGet = actionOnGet;
                m_ActionOnRelease = actionOnRelease;
            }
    
            public T Get()
            {
                T element = m_Stack.Pop();
                if (m_ActionOnGet != null)
                    m_ActionOnGet(element);
                return element;
            }
    
            public void Release(T element)
            {
                if (m_Stack.Count > 0 && ReferenceEquals(m_Stack.Peek(), element))
                    Debug.LogError("Internal error. Trying to destroy object that is already released to pool.");
                if (m_ActionOnRelease != null)
                    m_ActionOnRelease(element);
                m_Stack.Push(element);
            }
        }
    }
    ObjectPool/ObjectPool
    using UnityEngine;
    using System.Collections;
    
    namespace LuaFramework {
    
        public class TestObjectClass {
    
            public string name;
            public int value1;
            public float value2;
    
            // Use this for initialization
            public TestObjectClass(string name, int value1, float value2) {
                this.name = name;
                this.value1 = value1;
                this.value2 = value2;
            }
    
            public string ToString() {
                return string.Format("name={0} value1={1} = value2={2}", name, value1, value2);
            }
        }
    }
    ObjectPool/TestObjectClass
    using UnityEngine;
    using System.Collections.Generic;
    using System.Reflection;
    using LuaInterface;
    using System;
    
    namespace LuaFramework {
        public static class LuaHelper {
    
            /// <summary>
            /// getType
            /// </summary>
            /// <param name="classname"></param>
            /// <returns></returns>
            public static System.Type GetType(string classname) {
                Assembly assb = Assembly.GetExecutingAssembly();  //.GetExecutingAssembly();
                System.Type t = null;
                t = assb.GetType(classname); ;
                if (t == null) {
                    t = assb.GetType(classname);
                }
                return t;
            }
    
            /// <summary>
            /// 面板管理器
            /// </summary>
            public static PanelManager GetPanelManager() {
                return AppFacade.Instance.GetManager<PanelManager>(ManagerName.Panel);
            }
    
            /// <summary>
            /// 资源管理器
            /// </summary>
            public static ResourceManager GetResManager() {
                return AppFacade.Instance.GetManager<ResourceManager>(ManagerName.Resource);
            }
    
            /// <summary>
            /// 网络管理器
            /// </summary>
            public static NetworkManager GetNetManager() {
                return AppFacade.Instance.GetManager<NetworkManager>(ManagerName.Network);
            }
    
            /// <summary>
            /// 音乐管理器
            /// </summary>
            public static SoundManager GetSoundManager() {
                return AppFacade.Instance.GetManager<SoundManager>(ManagerName.Sound);
            }
    
    
            /// <summary>
            /// pbc/pblua函数回调
            /// </summary>
            /// <param name="func"></param>
            public static void OnCallLuaFunc(LuaByteBuffer data, LuaFunction func) {
                if (func != null) func.Call(data);
                Debug.LogWarning("OnCallLuaFunc length:>>" + data.buffer.Length);
            }
    
            /// <summary>
            /// cjson函数回调
            /// </summary>
            /// <param name="data"></param>
            /// <param name="func"></param>
            public static void OnJsonCallFunc(string data, LuaFunction func) {
                Debug.LogWarning("OnJsonCallback data:>>" + data + " lenght:>>" + data.Length);
                if (func != null) func.Call(data);
            }
        }
    }
    Utility/LuaHelper
    using UnityEngine;
    using System;
    using System.IO;
    using System.Text;
    using System.Collections;
    using System.Collections.Generic;
    using System.Security.Cryptography;
    using System.Text.RegularExpressions;
    using LuaInterface;
    using LuaFramework;
    
    #if UNITY_EDITOR
    using UnityEditor;
    #endif
    
    namespace LuaFramework {
        public class Util {
            private static List<string> luaPaths = new List<string>();
    
            public static int Int(object o) {
                return Convert.ToInt32(o);
            }
    
            public static float Float(object o) {
                return (float)Math.Round(Convert.ToSingle(o), 2);
            }
    
            public static long Long(object o) {
                return Convert.ToInt64(o);
            }
    
            public static int Random(int min, int max) {
                return UnityEngine.Random.Range(min, max);
            }
    
            public static float Random(float min, float max) {
                return UnityEngine.Random.Range(min, max);
            }
    
            public static string Uid(string uid) {
                int position = uid.LastIndexOf('_');
                return uid.Remove(0, position + 1);
            }
    
            public static long GetTime() {
                TimeSpan ts = new TimeSpan(DateTime.UtcNow.Ticks - new DateTime(1970, 1, 1, 0, 0, 0).Ticks);
                return (long)ts.TotalMilliseconds;
            }
    
            /// <summary>
            /// 搜索子物体组件-GameObject版
            /// </summary>
            public static T Get<T>(GameObject go, string subnode) where T : Component {
                if (go != null) {
                    Transform sub = go.transform.Find(subnode);
                    if (sub != null) return sub.GetComponent<T>();
                }
                return null;
            }
    
            /// <summary>
            /// 搜索子物体组件-Transform版
            /// </summary>
            public static T Get<T>(Transform go, string subnode) where T : Component {
                if (go != null) {
                    Transform sub = go.Find(subnode);
                    if (sub != null) return sub.GetComponent<T>();
                }
                return null;
            }
    
            /// <summary>
            /// 搜索子物体组件-Component版
            /// </summary>
            public static T Get<T>(Component go, string subnode) where T : Component {
                return go.transform.Find(subnode).GetComponent<T>();
            }
    
            /// <summary>
            /// 添加组件
            /// </summary>
            public static T Add<T>(GameObject go) where T : Component {
                if (go != null) {
                    T[] ts = go.GetComponents<T>();
                    for (int i = 0; i < ts.Length; i++) {
                        if (ts[i] != null) GameObject.Destroy(ts[i]);
                    }
                    return go.gameObject.AddComponent<T>();
                }
                return null;
            }
    
            /// <summary>
            /// 添加组件
            /// </summary>
            public static T Add<T>(Transform go) where T : Component {
                return Add<T>(go.gameObject);
            }
    
            /// <summary>
            /// 查找子对象
            /// </summary>
            public static GameObject Child(GameObject go, string subnode) {
                return Child(go.transform, subnode);
            }
    
            /// <summary>
            /// 查找子对象
            /// </summary>
            public static GameObject Child(Transform go, string subnode) {
                Transform tran = go.Find(subnode);
                if (tran == null) return null;
                return tran.gameObject;
            }
    
            /// <summary>
            /// 取平级对象
            /// </summary>
            public static GameObject Peer(GameObject go, string subnode) {
                return Peer(go.transform, subnode);
            }
    
            /// <summary>
            /// 取平级对象
            /// </summary>
            public static GameObject Peer(Transform go, string subnode) {
                Transform tran = go.parent.Find(subnode);
                if (tran == null) return null;
                return tran.gameObject;
            }
    
            /// <summary>
            /// 计算字符串的MD5值
            /// </summary>
            public static string md5(string source) {
                MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
                byte[] data = System.Text.Encoding.UTF8.GetBytes(source);
                byte[] md5Data = md5.ComputeHash(data, 0, data.Length);
                md5.Clear();
    
                string destString = "";
                for (int i = 0; i < md5Data.Length; i++) {
                    destString += System.Convert.ToString(md5Data[i], 16).PadLeft(2, '0');
                }
                destString = destString.PadLeft(32, '0');
                return destString;
            }
    
            /// <summary>
            /// 计算文件的MD5值
            /// </summary>
            public static string md5file(string file) {
                try {
                    FileStream fs = new FileStream(file, FileMode.Open);
                    System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
                    byte[] retVal = md5.ComputeHash(fs);
                    fs.Close();
    
                    StringBuilder sb = new StringBuilder();
                    for (int i = 0; i < retVal.Length; i++) {
                        sb.Append(retVal[i].ToString("x2"));
                    }
                    return sb.ToString();
                } catch (Exception ex) {
                    throw new Exception("md5file() fail, error:" + ex.Message);
                }
            }
    
            /// <summary>
            /// 清除所有子节点
            /// </summary>
            public static void ClearChild(Transform go) {
                if (go == null) return;
                for (int i = go.childCount - 1; i >= 0; i--) {
                    GameObject.Destroy(go.GetChild(i).gameObject);
                }
            }
    
            /// <summary>
            /// 清理内存
            /// </summary>
            public static void ClearMemory() {
                GC.Collect(); Resources.UnloadUnusedAssets();
                LuaManager mgr = AppFacade.Instance.GetManager<LuaManager>(ManagerName.Lua);
                if (mgr != null) mgr.LuaGC();
            }
    
            /// <summary>
            /// 取得数据存放目录
            /// </summary>
            public static string DataPath {
                get {
                    string game = AppConst.AppName.ToLower();
                    if (Application.isMobilePlatform) {
                        return Application.persistentDataPath + "/" + game + "/";
                    }
                    if (AppConst.DebugMode) {
                        return Application.dataPath + "/" + AppConst.AssetDir + "/";
                    }
                    if (Application.platform == RuntimePlatform.OSXEditor) {
                        int i = Application.dataPath.LastIndexOf('/');
                        return Application.dataPath.Substring(0, i + 1) + game + "/";
                    }
                    return "c:/" + game + "/";
                }
            }
    
            public static string GetRelativePath() {
                if (Application.isEditor)
                    return "file://" + System.Environment.CurrentDirectory.Replace("\", "/") + "/Assets/" + AppConst.AssetDir + "/";
                else if (Application.isMobilePlatform || Application.isConsolePlatform)
                    return "file:///" + DataPath;
                else // For standalone player.
                    return "file://" + Application.streamingAssetsPath + "/";
            }
    
            /// <summary>
            /// 取得行文本
            /// </summary>
            public static string GetFileText(string path) {
                return File.ReadAllText(path);
            }
    
            /// <summary>
            /// 网络可用
            /// </summary>
            public static bool NetAvailable {
                get {
                    return Application.internetReachability != NetworkReachability.NotReachable;
                }
            }
    
            /// <summary>
            /// 是否是无线
            /// </summary>
            public static bool IsWifi {
                get {
                    return Application.internetReachability == NetworkReachability.ReachableViaLocalAreaNetwork;
                }
            }
    
            /// <summary>
            /// 应用程序内容路径
            /// </summary>
            public static string AppContentPath() {
                string path = string.Empty;
                switch (Application.platform) {
                    case RuntimePlatform.Android:
                        path = "jar:file://" + Application.dataPath + "!/assets/";
                    break;
                    case RuntimePlatform.IPhonePlayer:
                        path = Application.dataPath + "/Raw/";
                    break;
                    default:
                        path = Application.dataPath + "/" + AppConst.AssetDir + "/";
                    break;
                }
                return path;
            }
    
            public static void Log(string str) {
                Debug.Log(str);
            }
    
            public static void LogWarning(string str) {
                Debug.LogWarning(str);
            }
    
            public static void LogError(string str) {
                Debug.LogError(str);
            }
    
            /// <summary>
            /// 防止初学者不按步骤来操作
            /// </summary>
            /// <returns></returns>
            public static int CheckRuntimeFile() {
                if (!Application.isEditor) return 0;
                string streamDir = Application.dataPath + "/StreamingAssets/";
                if (!Directory.Exists(streamDir)) {
                    return -1;
                } else {
                    string[] files = Directory.GetFiles(streamDir);
                    if (files.Length == 0) return -1;
    
                    if (!File.Exists(streamDir + "files.txt")) {
                        return -1;
                    }
                }
                string sourceDir = AppConst.FrameworkRoot + "/ToLua/Source/Generate/";
                if (!Directory.Exists(sourceDir)) {
                    return -2;
                } else {
                    string[] files = Directory.GetFiles(sourceDir);
                    if (files.Length == 0) return -2;
                }
                return 0;
            }
    
            /// <summary>
            /// 执行Lua方法
            /// </summary>
            public static object[] CallMethod(string module, string func, params object[] args) {
                LuaManager luaMgr = AppFacade.Instance.GetManager<LuaManager>(ManagerName.Lua);
                if (luaMgr == null) return null;
                return luaMgr.CallFunction(module + "." + func, args);
            }
    
                    /// <summary>
            /// 检查运行环境
            /// </summary>
            public static bool CheckEnvironment() {
    #if UNITY_EDITOR
                int resultId = Util.CheckRuntimeFile();
                if (resultId == -1) {
                    Debug.LogError("没有找到框架所需要的资源,单击Game菜单下Build xxx Resource生成!!");
                    EditorApplication.isPlaying = false;
                    return false;
                } else if (resultId == -2) {
                    Debug.LogError("没有找到Wrap脚本缓存,单击Lua菜单下Gen Lua Wrap Files生成脚本!!");
                    EditorApplication.isPlaying = false;
                    return false;
                }
                if (Application.loadedLevelName == "Test" && !AppConst.DebugMode) {
                    Debug.LogError("测试场景,必须打开调试模式,AppConst.DebugMode = true!!");
                    EditorApplication.isPlaying = false;
                    return false;
                }
    #endif
                return true;
            }
        }
    }
    Utility/Util
    using UnityEngine;
    using LuaFramework;
    using System.Collections.Generic;
    
    public class AppView : View {
        private string message;
    
        ///<summary>
        /// 监听的消息
        ///</summary>
        List<string> MessageList {
            get {
                return new List<string>()
                { 
                    NotiConst.UPDATE_MESSAGE,
                    NotiConst.UPDATE_EXTRACT,
                    NotiConst.UPDATE_DOWNLOAD,
                    NotiConst.UPDATE_PROGRESS,
                };
            }
        }
    
        void Awake() {
            RemoveMessage(this, MessageList);
            RegisterMessage(this, MessageList);
        }
    
        /// <summary>
        /// 处理View消息
        /// </summary>
        /// <param name="message"></param>
        public override void OnMessage(IMessage message) {
            string name = message.Name;
            object body = message.Body;
            switch (name) {
                case NotiConst.UPDATE_MESSAGE:      //更新消息
                    UpdateMessage(body.ToString());
                break;
                case NotiConst.UPDATE_EXTRACT:      //更新解压
                    UpdateExtract(body.ToString());
                break;
                case NotiConst.UPDATE_DOWNLOAD:     //更新下载
                    UpdateDownload(body.ToString());
                break;
                case NotiConst.UPDATE_PROGRESS:     //更新下载进度
                    UpdateProgress(body.ToString());
                break;
            }
        }
    
        public void UpdateMessage(string data) {
            this.message = data;
        }
    
        public void UpdateExtract(string data) {
            this.message = data;
        }
    
        public void UpdateDownload(string data) {
            this.message = data;
        }
    
        public void UpdateProgress(string data) {
            this.message = data;
        }
    
        void OnGUI() {
            GUI.Label(new Rect(10, 120, 960, 50), message);
    
            GUI.Label(new Rect(10, 0, 500, 50), "(1) 单击 "Lua/Gen Lua Wrap Files"。");
            GUI.Label(new Rect(10, 20, 500, 50), "(2) 运行Unity游戏");
            GUI.Label(new Rect(10, 40, 500, 50), "PS: 清除缓存,单击"Lua/Clear LuaBinder File + Wrap Files"。");
            GUI.Label(new Rect(10, 60, 900, 50), "PS: 若运行到真机,请设置Const.DebugMode=false,本地调试请设置Const.DebugMode=true");
            GUI.Label(new Rect(10, 80, 500, 50), "PS: 加Unity+ulua技术讨论群:>>341746602");
        }
    }
    View/AppView
    using UnityEngine;
    using System.Collections;
    
    namespace LuaFramework {
    
        /// <summary>
        /// </summary>
        public class Main : MonoBehaviour {
    
            void Start() {
                AppFacade.Instance.StartUp();   //启动游戏
            }
        }
    }
    Main
  • 相关阅读:
    如何实现清浮动(转载)
    js动态删除某一行,内容超出单元格后超出的部分用省略号代替
    jquery页面隐藏和展开之间切换
    比较jquery中的after(),append(),appendTo()方法
    如何使用git管理代码
    网页游戏常见外挂原理及防御
    JQuery实现页面刷新后菜单保留鼠标点击addclass的样式
    【查询】—Entity Framework实例详解
    SQL Server清除连接过的服务器名称列表
    WebBrowser.ExecWB的完整说明
  • 原文地址:https://www.cnblogs.com/revoid/p/11422924.html
Copyright © 2020-2023  润新知