1. 程式人生 > >使用IDEA進行Lua程式碼除錯、自動提示、程式碼跳轉、智慧重新命名

使用IDEA進行Lua程式碼除錯、自動提示、程式碼跳轉、智慧重新命名

試了幾個Lua IDE後,Lua Studio、Lua Glider、VS+babelua外掛、Sublime都不是特別滿意。直到發現了國人自創的另一個神奇工具:基於IDEA的EmmyLua外掛。該外掛功能非常完整:斷點除錯、自動提示、程式碼跳轉、智慧重新命名等,可以極大地提高Lua程式設計的速度。介面也比較舒服。

安裝步驟

下載、安裝並破解IntelliJ IDEA(我的版本是目前最新的2017.3.4) 安裝EmmyLua外掛 建議直接在IDEA工具內搜尋外掛安裝(當然也可以下載外掛到硬碟安裝)。 (1)在啟動介面點選Configure-Plugins: 在這裡插入圖片描述

(2)搜尋EmmyLua,然後點Search in repositories: 在這裡插入圖片描述

(3)點選右邊的Install綠色按鈕。安裝完需要重啟IDEA。 配置SDK,預設是Path路徑需要有一個Lua直譯器(lua.exe)。你可以在建立專案時指定其他目錄。 配置其他事項。 (1)將*.txt識別成lua檔案: 在這裡插入圖片描述

(2)忽略程式碼提示大小寫差別:

在這裡插入圖片描述

建立專案

建立普通Lua專案(不依賴其他程式,如遊戲引擎): New-Project,然後next,填專案名、路徑,點選finish。 在專案檢視的src資料夾New一個Lua檔案,可以自己print()一下,Run一下,看看有沒有輸出,有的話,說明SDK配置正確。

在這裡插入圖片描述 在這裡插入圖片描述

建立Unity引擎Lua專案 New-Modules from existing sources(注意不要選錯,這裡建立的是Modules,不是Project,否則等下匯入不了api自動提示的library)。【這裡有一個IDE Bug:第一次建立Modules,會在資料夾裡生成一個.iml檔案。但是如果資料夾裡本來就有.iml檔案,以後再點Modules from existing sources就會無法生成Modules,也就無法匯入library。這個Bug我折騰了一晚上才發現的!必須刪掉.iml檔案,才可以重新建立Modules】 然後選擇Unity資料夾的Lua訪問根目錄,我選的是Resources資料夾,因為可以從Resources作為根目錄搜尋lua檔案。 然後我們測試一下斷點除錯功能。開啟其中一個Lua檔案,設定斷點: 在這裡插入圖片描述

然後Run-Attach To Local Process: 在這裡插入圖片描述

選擇Unity程序,觸發斷點,說明能斷點除錯:

在這裡插入圖片描述

Unity API程式碼提示

現在Unity API程式碼提示是沒有的,因為我們還沒匯入API描述的library。這個library根據你選擇的Lua中介軟體不同而不同,所以建議是自己匯出。我的Lua中介軟體是SLua。這裡以SLua為例。 1.開啟SLua官方自帶的Unity專案,在Slua-Editor下面,新建一個SLuaApiExporter.cs指令碼: 在這裡插入圖片描述

2.輸入如下程式碼:

using System;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEditor;
using SLua;
using System.IO;
using UnityEngine;

namespace Slua
{
    public static class EmmyLuaApiExporter
    {
        [MenuItem("SLua/匯出EmmyLuaApi", false, 14)]
        static void Gen()
        {
            string path = "./EmmyApi/";
            if (Directory.Exists(path))
            {
                Directory.Delete(path, true);
            }
            Directory.CreateDirectory(path);
            //UnityEngine
            GenAssembly("UnityEngine", path);
            //GenAssembly("UnityEngine.UI", path);
            GenCustom(path);
        }

        public static void GenAssembly(string name, string path)
        {
            List<string> excludeList;
            List<string> includeList;
            CustomExport.OnGetNoUseList(out excludeList);
            CustomExport.OnGetUseList(out includeList);
            Type[] types = Assembly.Load(name).GetTypes();
            foreach (Type t in types)
            {
                if (LuaCodeGen.filterType(t, excludeList, includeList))
                {
                    GenType(t, false, path);
                }
            }
        }

        public static void GenCustom(string path)
        {
            Type[] types = Assembly.Load("Assembly-CSharp-firstpass").GetTypes();
            foreach (Type t in types)
            {
                if (t.IsDefined(typeof(CustomLuaClassAttribute), false))
                {
                    GenType(t, true, path);
                }
            }

            types = Assembly.Load("Assembly-CSharp").GetTypes();
            foreach (Type t in types)
            {
                if (t.IsDefined(typeof(CustomLuaClassAttribute), false))
                {
                    GenType(t, true, path);
                }
            }
        }
        public static void GenType(Type t, bool custom, string path)
        {
            if (!CheckType(t, custom))
                return;
            //TODO System.MulticastDelegate
            var sb = new StringBuilder();
            if (!CheckType(t.BaseType, custom))
                sb.AppendFormat("
[email protected]
{0}\n", t.Name); else sb.AppendFormat("[email protected] {0} : {1}\n", t.Name, t.BaseType.Name); GenTypeField(t, sb); sb.AppendFormat("local {0}={{ }}\n", t.Name); GenTypeMehod(t, sb); sb.AppendFormat("{0}.{1} = {2}", t.Namespace, t.Name, t.Name); File.WriteAllText(path + t.FullName + ".lua", sb.ToString(), Encoding.UTF8); } static bool CheckType(Type t, bool custom) { if (t == null) return false; if (t == typeof(System.Object)) return false; if (t.IsGenericTypeDefinition) return false; if (t.IsDefined(typeof(ObsoleteAttribute), false)) return false; if (t == typeof(YieldInstruction)) return false; if (t == typeof(Coroutine)) return false; if (t.IsNested) return false; if (custom && !t.IsDefined(typeof(CustomLuaClassAttribute), false)) return false; return true; } public static void GenTypeField(Type t, StringBuilder sb) { FieldInfo[] fields = t.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly); foreach(var field in fields) { if (field.IsDefined(typeof(DoNotToLuaAttribute), false)) continue; sb.AppendFormat("[email protected] public {0} {1}\n", field.Name, GetLuaType(field.FieldType)); } PropertyInfo[] properties = t.GetProperties(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly); foreach (var pro in properties) { if (pro.IsDefined(typeof(DoNotToLuaAttribute), false)) continue; sb.AppendFormat("[email protected] public {0} {1}\n", pro.Name, GetLuaType(pro.PropertyType)); } } public static void GenTypeMehod(Type t, StringBuilder sb) { MethodInfo[] methods = t.GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly); foreach (var method in methods) { if (method.IsGenericMethod) continue; if (method.IsDefined(typeof(DoNotToLuaAttribute), false)) continue; if(method.Name.StartsWith("get_") || method.Name.StartsWith("set_")) continue; sb.AppendLine("[email protected]"); var paramstr = new StringBuilder(); foreach (var param in method.GetParameters()) { sb.AppendFormat("[email protected] {0} {1}\n", param.Name, GetLuaType(param.ParameterType)); if (paramstr.Length != 0) { paramstr.Append(", "); } paramstr.Append(param.Name); } sb.AppendFormat("[email protected] {0}\n", method.ReturnType == null ? "void" : GetLuaType(method.ReturnType)); if( method.IsStatic) { sb.AppendFormat("function {0}.{1}({2}) end\n", t.Name, method.Name, paramstr); } else { sb.AppendFormat("function {0}:{1}({2}) end\n", t.Name, method.Name, paramstr); } } } static string GetLuaType(Type t) { if (t.IsEnum //|| t == typeof(ulong) //|| t == typeof(long) //|| t == typeof(int) //|| t == typeof(uint) //|| t == typeof(float) || t == typeof(double) //|| t == typeof(byte) //|| t == typeof(ushort) //|| t == typeof(short) ) return "number"; if (t == typeof(bool)) return "bool"; if (t == typeof(string)) return "string"; if (t == typeof(void)) return "void"; return t.Name; } } }

3.在Unity編輯器中點選SLua-匯出EmmyLuaApi 在這裡插入圖片描述

4.看到Unity工程專案會多出一個EmmyApi資料夾: 在這裡插入圖片描述

5.將其打包成zip檔案(注意不能是rar、7z其它壓縮格式!) 在這裡插入圖片描述

6.在IDEA中點選File-Project Structure,Modules-選擇我們的Modules-Dependencies,+號-Library-Lua Zip Library,選擇我們剛才打包的zip檔案。然後一直OK儲存就行了。

在這裡插入圖片描述 在這裡插入圖片描述

7.測試Unity API提示功能: 在這裡插入圖片描述

成功!

其它功能

程式碼跳轉: 在這裡插入圖片描述

智慧重新命名:

在這裡插入圖片描述

後續

本教程就到這裡結束了,但是該外掛還有許多有用的功能,可以自行探索,也可以加入EmmyLua的官方QQ群:29850775。群裡面有許多教程,本文所用的API匯出程式碼也是從群檔案裡拿出來改的。

最後感謝EmmyLua的作者們無私開源編寫了這個強大的外掛。