XLua 热更新方案
1、下载XLua最新框架zip(https://github.com/Tencent/xLua)2、导入最新的XLua框架(按文件原始路径,导入Plugins、XLua、Tool三个文件)
(1)项目Asset目录下导入Plugings和XLua;
(2)Asset同级目录下导入Tool工具;
(3)开启宏 HOTFIX_ENABLE,File---->buildSetting---->playerSetting---->scriptsDefineSymbols里添加;HOTFIX_ENABLE。(注意 :编辑器、各手机平台这个宏要分别设置!如果是自动化打包,要注意在代码里头用API设置的宏是不生效的,需要在编辑器设置)
3、C#逻辑下热更新逻辑入口(可以放在Camera下或在检测版本后激活该脚本)
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using XLua;
public class FishHotFix_Inlet : MonoBehaviour
{
LuaEnv luaenv = null;
void Start()
{
luaenv = new LuaEnv();
//luaenv.DoString("print('hello world')");
//luaenv.DoString("require 'fishHotFixPrint'");
//luaenv.DoString(@"
// xlua.hotfix(CS.Inlet, 'FTest', function(self)
// print('inlet .. hotfix .. FTest')
// end)
//");
//luaenv.DoString("require 'fishHotFix'");
//luaenv.AddLoader((ref string filename) =>
//{
// if (filename == "fishHotFix")
// {
// string path = @"C:\Users\User\Desktop\XLua\fishHotFix.lua.txt";
// return System.Text.Encoding.UTF8.GetBytes(File.ReadAllText(path));
// }
// return null;
//});
//luaenv.DoString("require 'fishHotFix'");
luaenv.AddLoader(MyLoader);//加载.lua文件
luaenv.DoString("require 'fishHotFix'");//执行HotFix.lua
}
private byte[] MyLoader(ref string filePath)
{
//string path = @"C:\Users\User\Desktop\XLua\" + filePath + ".lua.txt";
string path = Application.streamingAssetsPath + "/fishhotfix/" + filePath + ".lua.txt";
return System.Text.Encoding.UTF8.GetBytes(File.ReadAllText(path));
}
void Update()
{
if (luaenv != null)
{
luaenv.Tick();
}
}
void OnDestroy()
{
//luaenv Dispose之前注销
//HotFixDispose.lua,注销lua执行方法
luaenv.DoString("require 'fishHotFixDispose'");
luaenv.Dispose();
}
}4、自动识别文件配置、lua调用C#、C#调用lua(放到Assets\XLua\Editor目录下)
using System.Collections.Generic;
using System;
using XLua;
using System.Reflection;
using System.Linq;
using UnityEngine;
public static class HotFixConfig
{
//筛选过的文件具有热更功能==类名添加
public static List<Type> by_property
{
// X:\lemongame\slgrpg_2d\3d\slgrogue\Assets\ProjectTemplate\Plugins\Sirenix\Assemblies\Sirenix.OdinInspector.Editor.dll
get
{
return (from type in Assembly.Load("Assembly-CSharp").GetTypes()
where type.Namespace == null || !type.Namespace.StartsWith("XLua")
select type).ToList();//文件筛选
}
}
//lua中要使用到C#库的配置,比如C#标准库,或者Unity API,第三方库等。
public static List<Type> LuaCallCSharp = new List<Type>() {
typeof(System.Object),
typeof(UnityEngine.Object),
typeof(Vector2),
typeof(Vector3),
typeof(Vector4),
typeof(Quaternion),
typeof(Color),
typeof(Ray),
typeof(Bounds),
typeof(Ray2D),
typeof(Time),
typeof(GameObject),
typeof(Component),
typeof(Behaviour),
typeof(Transform),
typeof(Resources),
typeof(TextAsset),
typeof(Keyframe),
typeof(AnimationCurve),
typeof(AnimationClip),
typeof(MonoBehaviour),
typeof(ParticleSystem),
typeof(SkinnedMeshRenderer),
typeof(Renderer),
typeof(WWW),
//typeof(Light),
typeof(Mathf),
typeof(System.Collections.Generic.List<int>),
typeof(Action<string>),
typeof(UnityEngine.Debug)
};
//C#静态调用Lua的配置(包括事件的原型),仅可以配delegate,interface
public static List<Type> CSharpCallLua = new List<Type>() {
typeof(Action),
typeof(Func<double, double, double>),
typeof(Action<string>),
typeof(Action<double>),
typeof(UnityEngine.Events.UnityAction),
typeof(System.Collections.IEnumerator)
};
//黑名单
public static List<List<string>> BlackList = new List<List<string>>(){
new List<string>(){"System.Xml.XmlNodeList", "ItemOf"},
new List<string>(){"UnityEngine.WWW", "movie"},
#if UNITY_WEBGL
new List<string>(){"UnityEngine.WWW", "threadPriority"},
#endif
new List<string>(){"UnityEngine.Texture2D", "alphaIsTransparency"},
new List<string>(){"UnityEngine.Security", "GetChainOfTrustValue"},
new List<string>(){"UnityEngine.CanvasRenderer", "onRequestRebuild"},
//new List<string>(){"UnityEngine.Light", "areaSize"},
//new List<string>(){"UnityEngine.Light", "lightmapBakeType"},
//new List<string>(){"UnityEngine.Light", "shadowAngle"},
//new List<string>(){"UnityEngine.Light", "shadowRadius"},
//new List<string>(){"UnityEngine.Light", "SetLightDirty"},
new List<string>(){"UnityEngine.WWW", "MovieTexture"},
new List<string>(){"UnityEngine.WWW", "GetMovieTexture"},
new List<string>(){"UnityEngine.AnimatorOverrideController", "PerformOverrideClipListCleanup"},
#if !UNITY_WEBPLAYER
new List<string>(){"UnityEngine.Application", "ExternalEval"},
#endif
new List<string>(){"UnityEngine.GameObject", "networkView"}, //4.6.2 not support
new List<string>(){"UnityEngine.Component", "networkView"},//4.6.2 not support
new List<string>(){"System.IO.FileInfo", "GetAccessControl", "System.Security.AccessControl.AccessControlSections"},
new List<string>(){"System.IO.FileInfo", "SetAccessControl", "System.Security.AccessControl.FileSecurity"},
new List<string>(){"System.IO.DirectoryInfo", "GetAccessControl", "System.Security.AccessControl.AccessControlSections"},
new List<string>(){"System.IO.DirectoryInfo", "SetAccessControl", "System.Security.AccessControl.DirectorySecurity"},
new List<string>(){"System.IO.DirectoryInfo", "CreateSubdirectory", "System.String", "System.Security.AccessControl.DirectorySecurity"},
new List<string>(){"System.IO.DirectoryInfo", "Create", "System.Security.AccessControl.DirectorySecurity"},
new List<string>(){"UnityEngine.MonoBehaviour", "runInEditMode"},
};
#if UNITY_2018_1_OR_NEWER
public static Func<MemberInfo, bool> MethodFilter = (memberInfo) =>
{
if (memberInfo.DeclaringType.IsGenericType && memberInfo.DeclaringType.GetGenericTypeDefinition() == typeof(Dictionary<,>))
{
if (memberInfo.MemberType == MemberTypes.Constructor)
{
ConstructorInfo constructorInfo = memberInfo as ConstructorInfo;
var parameterInfos = constructorInfo.GetParameters();
if (parameterInfos.Length > 0)
{
if (typeof(System.Collections.IEnumerable).IsAssignableFrom(parameterInfos.ParameterType))
{
return true;
}
}
}
else if (memberInfo.MemberType == MemberTypes.Method)
{
var methodInfo = memberInfo as MethodInfo;
if (methodInfo.Name == "TryAdd" || methodInfo.Name == "Remove" && methodInfo.GetParameters().Length == 2)
{
return true;
}
}
}
return false;
};
#endif
}5、Asset/StreamingAssets的lua文件(测试lua是否执行修改原有C#逻辑,可以按具体项目来编写)
(1)fishHotFix.lua.txt
local util = require '../../XLua/Resources/xlua/util'
--1、执行新的逻辑
xlua.hotfix(CS.FUIWindow_CoverUIVO, 'FTest', function(self)
CS.UnityEngine.Debug.Log("hotfix .. FTest .. by .. streamingAssetsPath .. lua")
end)
--2、执行原来的逻辑
util.hotfix_ex(CS.FUIWindow_CoverUIVO, 'FTest1', function(self)
self:FTest1()
CS.UnityEngine.Debug.Log("hotfix .. FUIWindow_CoverUIVO .. FTest .. 1")
end)
--3、执行协程
xlua.hotfix(CS.FUIWindow_CoverUIVO, 'FIEnumTest', function(self)
return util.cs_generator(function()
print('hotfix .. FIEnumTest .. start')
coroutine.yield(CS.UnityEngine.WaitForSeconds(3))
print('hotfix .. FIEnumTest .. 3f')
end)
end)
--4、修改界面控件逻辑
xlua.hotfix(CS.FUIWindow_CoverUIVO, 'SetLoginType', function(self, login)
print('hotfix .. SetLoginType .. login =', login, not login)
self._fui.m_btn_login.visible = login
self._fui.m_progressbar.visible = not login
self._fui.m_text.visible = not login
print('hotfix .. SetLoginType ..')
end)
--5、修改界面逻辑(注意添加CS,调用属性和方法)
util.hotfix_ex(CS.FUIWindow_MainTopUIVO, 'UpdateCurrency', function(self, notif)
self:UpdateCurrency(notif)
self._fui.m_Com_gold.m_title.text = 100
end)
--6、同级目录下lua逻辑
require 'fishHotFixPrint' (2)fishHotFixPrint.lua.txt
local util = require '../../XLua/Resources/xlua/util'
--修改(可以覆盖之前的)
util.hotfix_ex(CS.FUIWindow_MainTopUIVO, 'UpdateCurrency', function(self, notif)
self:UpdateCurrency(notif)
self._fui.m_Com_gold.m_title.text = 100
self._fui.m_Com_diamond.m_title.text = CS.UserInfo.Instance:GetCurrency(CS.CurrencyType.diamond) + 100
end) (3)fishHotFixDispose.lua.txt
--在LuaEnv Dispose之前注销
xlua.hotfix(CS.FUIWindow_CoverUIVO,'FTest',nil)
xlua.hotfix(CS.FUIWindow_CoverUIVO,'FTest1',nil)
xlua.hotfix(CS.FUIWindow_CoverUIVO,'FIEnumTest',nil)
xlua.hotfix(CS.FUIWindow_CoverUIVO,'SetLoginType',nil)
xlua.hotfix(CS.FUIWindow_MainTopUIVO,'UpdateCurrency',nil)6、Lua和C#的连接(不修改HotFixConfig配置文件不需要执行1、2步)
(1)清除C#和lua链接文件;
(2)生成链接的中间文件;
(3)注入(Unity启动游戏时,注入成功弹窗)
注入成功提示
7、使用
页:
[1]