using System.Collections.Generic; using UnityEngine; using XLua; using System; using System.IO; namespace BF { public class LuaManager : ManagerBase { #region override static LuaManager instance; public static LuaManager Create() { BFLog.LogAssert(instance == null, "This method only allows BFMain to call once"); instance = new LuaManager(); return instance; } LuaManager() { } public override void Init() { OnInit(); } public override void Update() { OnUpdate(); } public override void Destroy() { OnDestroy(); } #endregion internal LuaEnv luaEnv; const float GCInterval = 1; // 1 second float lastGCTime = 0; Dictionary luaScriptDict = new Dictionary(); Action luaUpdate; Action luaOnDestroy; Action luaOnLogMessageReceived; Action luaOnApplicationFocus; Action luaOnApplicationPause; Action luaOnApplicationQuit; Action gameInitSuccCallback; AssetBundleConfigCollection Abcc { get { return BFMain.Instance.ResMgr.AbConfigCollection; } } public bool DevExist = false; void OnInit() { if (luaEnv == null) { #if UNITY_EDITOR DevExist = Directory.Exists(Application.dataPath + "/Developer/lua"); #endif Application.logMessageReceived += OnLogMessageReceived; luaEnv = new LuaEnv(); luaEnv.AddBuildin("rapidjson", XLua.LuaDLL.Lua.LoadRapidJson); luaEnv.AddBuildin("lpeg", XLua.LuaDLL.Lua.LoadLpeg); luaEnv.AddBuildin("pb", XLua.LuaDLL.Lua.LoadLuaProfobuf); } } void OnLogMessageReceived(string message, string stackTrace, LogType type) { if (type == LogType.Error || type == LogType.Exception) { luaOnLogMessageReceived?.Invoke(message, stackTrace); } } /// /// 初始化首包lua /// public void InitFirstLua(LuaEnv.CustomLoader loader) { BFLog.Log("加载首包lua first.lua"); luaEnv.ClearLoader(); luaEnv.AddLoader(loader); luaEnv.DoString("require 'app/first/first'"); } /// /// 初始化main.lua 进入游戏 /// public void InitGame(Action gameInitSuccCallback) { this.gameInitSuccCallback = gameInitSuccCallback; luaEnv.ClearLoader(); luaEnv.AddLoader((ref string scriptPath) => { var text = LoadGameLuaScriptText(scriptPath); return text; }); luaEnv.DoString("require 'main'"); #if HOTFIX_ENABLE luaEnv.DoString("require 'app/hotfix/hotfixmain'"); #endif } byte[] LoadGameLuaScriptText(string scriptPath) { byte[] result = null; if (!luaScriptDict.TryGetValue(scriptPath, out result)) { #if !USE_AB && UNITY_EDITOR result = LoadLuaDeveloperMode(scriptPath); #else result = LoadLuaStandardMode(scriptPath); #endif if (result != null) { luaScriptDict.Add(scriptPath, result); } } return result; } public byte[] LoadLuaDeveloperMode(string scriptPath) { byte[] result = null; if (DevExist) { // 开发路径加载 var devLuaPath = Application.dataPath + "/Developer/lua/" + scriptPath + ".lua"; if (File.Exists(devLuaPath)) { result = File.ReadAllBytes(devLuaPath); } else { Debug.LogError("lua file is missing : " + devLuaPath); } } else { // 开发路径不存在,尝试bytes路径加载 var luaBytesPath = Application.dataPath + "/lua/" + scriptPath + ".lua.bytes"; if (File.Exists(luaBytesPath)) { result = File.ReadAllBytes(luaBytesPath); XLua.LuaDLL.Lua.decryptLua(ref result[0], result.Length); } else { Debug.LogError("lua file is missing : " + luaBytesPath); } } return result; } byte[] LoadLuaStandardMode(string scriptPath) { byte[] result = LoadLuaAB(scriptPath); if (result == null) { Debug.LogError("Lua assetBundle is missing : " + scriptPath + ".lua"); } return result; } byte[] LoadLuaAB(string scriptPath) { var luaPath = "assets/lua/" + scriptPath + ".lua.bytes"; var abConfig = Abcc.GetConfigByAssetPath(luaPath); string fullpath; if (abConfig.location == 1) { fullpath = Path.Combine(Application.persistentDataPath, "update", abConfig.assetBundlePath); } else { fullpath = Path.Combine(Application.streamingAssetsPath, abConfig.assetBundlePath); } var ab = AssetBundle.LoadFromFile(fullpath); var textAsset = ab.LoadAsset(luaPath); var bytes = textAsset.bytes.Clone() as byte[]; XLua.LuaDLL.Lua.decryptLua(ref bytes[0], bytes.Length); ab.Unload(true); return bytes; } public void GetGlobalLuaFunc() { luaEnv.Global.Get("luaUpdate", out luaUpdate); luaEnv.Global.Get("luaOnDestroy", out luaOnDestroy); luaEnv.Global.Get("luaOnLogMessageReceived", out luaOnLogMessageReceived); luaEnv.Global.Get("luaOnApplicationFocus", out luaOnApplicationFocus); luaEnv.Global.Get("luaOnApplicationPause", out luaOnApplicationPause); luaEnv.Global.Get("luaOnApplicationQuit", out luaOnApplicationQuit); } public void OnGameInitSucc() { BFLog.Log("OnGameInitSucc"); gameInitSuccCallback?.Invoke(); gameInitSuccCallback = null; BFMain.Instance.GameLaunchMgr.LaunchRequester.ClearLaunchSuccCallback(); } public void ClearCache() { luaScriptDict.Clear(); } public void LuaEnvTick() { luaEnv.Tick(); lastGCTime = Time.time; } public void LuaEnvFullGC(int count) { int defaultCheckCouunt = luaEnv.GetMaxCheckPerTick(); luaEnv.SetMaxCheckPerTick(count); LuaEnvTick(); luaEnv.SetMaxCheckPerTick(defaultCheckCouunt); } void OnUpdate() { luaUpdate?.Invoke(); if (Time.time - lastGCTime > GCInterval) { luaEnv.Tick(); lastGCTime = Time.time; } } public void OnApplicationFocus(bool hasFocus) { luaOnApplicationFocus?.Invoke(hasFocus); } public void OnApplicationPause(bool pauseStatus) { luaOnApplicationPause?.Invoke(pauseStatus); } public void OnApplicationQuit() { luaOnApplicationQuit?.Invoke(); } void OnDestroy() { luaOnDestroy?.Invoke(); luaOnDestroy = null; luaUpdate = null; luaOnApplicationFocus = null; luaOnApplicationPause = null; luaOnApplicationQuit = null; } public void Clear() { luaUpdate = null; luaOnDestroy = null; luaOnLogMessageReceived = null; luaOnApplicationFocus = null; luaOnApplicationPause = null; luaOnApplicationQuit = null; gameInitSuccCallback = null; } } }