zoukankan      html  css  js  c++  java
  • unity3d热更新解决方案,使用ulua插件开发的框架。

    ulua插件下载地址 www.ulua.org,下面要说的是ulua的开发框架。

    首先是 LuaLoader 类,它负责把一个 lua 的 table 加载起来,使此 lua 的 table 像一个 unity 的 component 一样挂在游戏对象上,代码如下:

    using LuaInterface;
    using System;
    using UnityEngine;
    
    public class LuaLoader : MonoBehaviour
    {
        public string Name;
    
        LuaTable m_table;
        LuaFunction m_updateFunc;
        LuaFunction m_fixedUpdateFunc;
    
        /// <summary>
        /// 通过 Name 名,加载对应的 lua table,并将之“挂”在游戏对象上。
        /// </summary>
        /// <returns>是否加载成功</returns>
        public bool Load()
        {
            if (string.IsNullOrEmpty(Name))
                return false;
    
            m_table = LuaHelper.GetLuaTable(Name);
            if (m_table == null)
                return false;
    
            // Init lua
            m_table["transform"] = transform;
            m_table["gameObject"] = gameObject;
    
            //
            m_updateFunc = GetMethod("Update");
            m_fixedUpdateFunc = GetMethod("FixedUpdate");
    
            return true;
        }
    
        void Awake()
        {
            if (Load())
                CallMethod("Awake");
            else
            {
                if (!string.IsNullOrEmpty(Name))        // 如果 Name 为空,可能是 Add component
                    throw new ArgumentNullException("Load lua table failed, no table in " + Name);
            }
        }
    
        void Start()
        {
            if (m_table == null)                        // 此处应为 Add component 的情况
            {
                if (string.IsNullOrEmpty(Name))
                    throw new ArgumentException("string.IsNullOrEmpty(Name)");
    
                if (!Load())
                    throw new ArgumentNullException("Load lua table failed, no table in " + Name);
            }
    
            CallMethod("Start");
        }
    
        void Update()
        {
            if (m_updateFunc != null)
                m_updateFunc.Call(Time.deltaTime);
        }
    
        void FixedUpdate()
        {
            if (m_fixedUpdateFunc != null)
                m_fixedUpdateFunc.Call();
        }
    
        void OnEnable()
        {
            CallMethod("OnEnable");
        }
    
        void OnDisable()
        {
            CallMethod("OnDisable");
        }
    
        void OnDestroy()
        {
            CallMethod("OnDestroy");
    
            // 释放内存
            m_table["transform"] = null;
            m_table["gameObject"] = null;
    
            m_table.Release();
            m_table = null;
    
            if (m_updateFunc != null)
                m_updateFunc.Release();
    
            if (m_fixedUpdateFunc != null)
                m_fixedUpdateFunc.Release();
    
            LuaScriptMgr.Instance.LuaGC();
        }
    
        LuaFunction GetMethod(string methodName)
        {
            return m_table != null ? m_table[methodName] as LuaFunction : null;
        }
    
        void CallMethod(string name)
        {
            var func = GetMethod(name);
    
            if (func != null)
            {
                func.Call();
                func.Release();     // 释放内存
            }
        }
    
        public LuaTable Table
        {
            get { return m_table; }
        }
    }
    LuaLoader

      

    其次是 lua 与 c# 的交互,提供了两个帮助类,一个是 LuaHelper ,与游戏逻辑无关的方法封装在里面;另外一个是 LuaUtils, lua 中要访问 c# 代码的方法(与游戏逻辑有关的)都封装在里面。

    LuaHelper 关键的几个方法代码如下:

    using LuaInterface;
    using Resource;
    using System;
    using System.IO;
    using System.Linq;
    using System.Security.Cryptography;
    using System.Text;
    using UnityEngine;
    using UObject = UnityEngine.Object;
    
    public static class LuaHelper
    {
        #region Lua
    
        public static LuaTable GetLuaComponent(Transform transform)
        {
            if (transform == null)
                throw new ArgumentNullException("transform");
    
            var loaders = transform.GetComponents<LuaLoader>();
            var rightLoader = loaders.FirstOrDefault(lt => lt.Table != null);
    
            return rightLoader != null ? rightLoader.Table : null;
        }
    
        public static LuaTable GetLuaComponent(GameObject gameObject)
        {
            return GetLuaComponent(gameObject.transform);
        }
    
        public static LuaTable GetLuaComponent(Transform transform, string type)
        {
            if (transform == null)
                throw new ArgumentNullException("transform");
            if (string.IsNullOrEmpty(type))
                throw new ArgumentException("type");
    
            var loaders = transform.GetComponents<LuaLoader>();
            var rightLoader = loaders.FirstOrDefault(lt => lt.Table != null && lt.Table.name == type);
    
            return rightLoader != null ? rightLoader.Table : null;
        }
    
        public static LuaTable GetLuaComponent(GameObject gameObject, string type)
        {
            return GetLuaComponent(gameObject.transform, type);
        }
    
        public static LuaTable AddLuaComponent(GameObject gameObject, string type)
        {
            var loader = gameObject.AddComponent<LuaLoader>();
            loader.Name = type;
            loader.Load();
            return loader.Table;
        }
    
        /// <summary>
        /// 从ab包中加载table,供lua使用
        /// </summary>
        /// <param name="name">table名</param>
        public static void LoadLuaTable(string name)
        {
            if (string.IsNullOrEmpty(name))
                throw new ArgumentException("name");
    
            LuaTable table = LuaScriptMgr.Instance.GetLuaTable(name);
    
            if (table == null)
            {
                using (var loadLua = new LoadLuaHandler(name))
                    LuaScriptMgr.Instance.DoString(loadLua.Text);
            }
        }
    
        public static LuaTable GetLuaTable(string name)
        {
            if (string.IsNullOrEmpty(name))
                throw new ArgumentException("name");
    
            LuaTable table = LuaScriptMgr.Instance.GetLuaTable(name);
    
            if (table == null)
            {
                using (var loadLua = new LoadLuaHandler(name))
                    LuaScriptMgr.Instance.DoString(loadLua.Text);
    
                table = LuaScriptMgr.Instance.GetLuaTable(name);
            }
    
            return table;
        }
    
        public static LuaFunction GetLuaFunction(string className, string funcName)
        {
            if (string.IsNullOrEmpty(className))
                throw new ArgumentException(className);
            if (string.IsNullOrEmpty(funcName))
                throw new ArgumentException(funcName);
    
            LuaTable table = GetLuaTable(className);
            return table[funcName] as LuaFunction;
        }
    
        public static object[] CallFunction(string className, string funcName, params object[] args)
        {
            LuaFunction func = GetLuaFunction(className, funcName);
            if (func == null)
                throw new ArgumentNullException(string.Format("Cann't find lua function: {0}.{1}", className, funcName));
    
            var returnArgs = args == null ? func.Call() : func.Call(args);
            func.Release();
    
            return returnArgs;
        }
    
        #endregion
    }
    LuaHelper

    另外,关于通过 lua 代码给c#打补丁的功能,是在 UIPanel OnEnable 的第一帧检测补丁和打补丁的,c#代码如下:

    using LuaInterface;
    using System;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class LuaPatchManager : IDisposable
    {
        List<Patch> m_patches;
    
        #region Singleton
    
        static LuaPatchManager s_instance;
    
        public static LuaPatchManager Instance
        {
            get { return s_instance; }
        }
    
        #endregion
    
        #region Patch
    
        class Patch : IDisposable
        {
            LuaFunction m_validate;
            LuaFunction m_correct;
    
            public Patch(LuaFunction validate, LuaFunction correct)
            {
                if (validate == null)
                    throw new ArgumentNullException("validate");
                if (correct == null)
                    throw new ArgumentNullException("correct");
    
                m_validate = validate;
                m_correct = correct;
            }
    
            public bool Validate(UIPanel uiPanel)
            {
                var objs = m_validate.Call(uiPanel);
                return (bool)objs[0];
            }
    
            public void Correct(UIPanel uiPanel)
            {
                m_correct.Call(uiPanel);
            }
    
            #region IDisposable
    
            public void Dispose()
            {
                Dispose(true);
                GC.SuppressFinalize(this);
            }
    
            void Dispose(bool disposing)
            {
                if (disposing)
                {
                    m_validate.Release();
                    m_validate = null;
                    m_correct.Release();
                    m_correct = null;
                }
            }
    
            ~Patch()
            {
                Dispose(false);
            }
    
            #endregion
        }
    
        #endregion
    
        private LuaPatchManager(LuaTable listTable)
        {
            if (listTable == null || listTable.Values.Count <= 0)
                throw new ArgumentException("listTable == null || listTable.Values.Count <= 0");
    
            m_patches = new List<Patch>();
    
            foreach (string name in listTable.Values)
            {
                var patch = LuaHelper.GetLuaTable(name);
                if (patch != null)
                {
                    var validateFunc = patch["Validate"] as LuaFunction;
                    var correctFunc = patch["Correct"] as LuaFunction;
    
                    if (validateFunc != null && correctFunc != null)
                        m_patches.Add(new Patch(validateFunc, correctFunc));
    
                    patch.Release();
                }
            }
    
            listTable.Release();
            LuaScriptMgr.Instance.LuaGC();
        }
    
        public static void Load()
        {
            LuaTable listTable = null;
            string targetFileName = "LuaPatchList";
    
            try
            {
                listTable = LuaHelper.GetLuaTable(targetFileName);
            }
            catch
            {
                Debug.LogWarning("No file: " + targetFileName);
            }
    
            if (listTable != null)
            {
                if (listTable.Values.Count > 0)
                    s_instance = new LuaPatchManager(listTable);
    
                listTable.Release();
            }
        }
    
        public void DoPatch(UIPanel uiPanel)
        {
            if (uiPanel == null)
                throw new ArgumentNullException("uiPanel");
    
            for (int i = 0; i < m_patches.Count; i++)
            {
                Patch p = m_patches[i];
                if (p.Validate(uiPanel))
                {
                    p.Correct(uiPanel);
                    break;
                }
            }
        }
    
        #region IDisposable
    
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    
        void Dispose(bool disposing)
        {
            if (disposing)
            {
                for (int i = 0; i < m_patches.Count; i++)
                    m_patches[i].Dispose();
    
                m_patches.Clear();
                m_patches = null;
            }
        }
    
        ~LuaPatchManager()
        {
            Dispose(false);
        }
    
        #endregion
    }
    LuaPatchManager

    lua代码如下:

    LuaPatchList=
    {
        "MainInfoControllerPatch",
    };
    LuaPatchList

    一个补丁的例子如下:

    MainInfoControllerPatch={};
    
    local function ClickTest()
        TipsShowController.Show("Who are you?");
    end
    
    -- 验证此uiPanel是否是希望打补丁的uiPanel --
    function MainInfoControllerPatch.Validate(uiPanel)
        return uiPanel.transform.parent~=nil and uiPanel.transform.parent.name=="MainInfoController(Clone)";
    end
    
    -- 纠正此uiPanel上的展示内容,执行方法等 --
    function MainInfoControllerPatch.Correct(uiPanel)
        local titleLabel=uiPanel.transform:Find("LabelName"):GetComponent("UILabel");
        titleLabel.text="TianJie";
    
        local mustBuyButton=uiPanel.transform:Find("ButtonFashion"):GetComponent("UIButton");
        mustBuyButton.onClick:Clear();
        EventDelegate.Add(mustBuyButton.onClick,DelegateFactory.EventDelegate_Callback(ClickTest));
    end
    Patch

    转载请注明出处:http://www.cnblogs.com/jietian331/p/4955282.html

  • 相关阅读:
    倒排索引
    线控的原理
    性格类型之ISFP艺术家型——有爱心的艺术工作者
    亚马逊面试题及解法
    关于过度设计的思考(zz)
    给Visual Studio 2010中文版添加Windows Phone 7模板
    MySQL性能优化zz
    上班玩游戏,老总是怎么知道的呢?
    基于AJAX的自动完成
    JavaScript在ASP.NET AJAX中的另类故事
  • 原文地址:https://www.cnblogs.com/jietian331/p/4955282.html
Copyright © 2011-2022 走看看