unity3d热更新解决方案,使用ulua插件开发的框架。

时间:2021-09-27 05:45:50

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[];
} 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 <= )
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 > )
s_instance = new LuaPatchManager(listTable); listTable.Release();
}
} public void DoPatch(UIPanel uiPanel)
{
if (uiPanel == null)
throw new ArgumentNullException("uiPanel"); for (int i = ; 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 = ; 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