The software involved in this article is: FairyGUI, VSCode
The code environment involves: Lua
VSCode plug-in: EmmyLua
Before writing the FairyGUI editor menu, understanding the API of FairyGUIEditor will effectively help us solve many problems. The extension of FairyGUI is implemented through the plug-in function that comes with the editor. In the plug-in, I use the lua environment template. Import the LuaAPI of the editor. The file can be found in the plug-in directory of the FairyGUI-Editor source code. Next, the corresponding API functions will be explained through functions.
The location of the plugin
If you can't find the plug-in panel, you can add it through "View → Plug-ins" or "Tools → Plug-ins".
1. Open the plug-in directory. The plug-in directory is under the "Project Directory/plugins" folder. Each plug-in corresponds to a subfolder.
2. Create a new plug-in
3. Refresh the plug-in list
The birth of a new plug-in
Click to create a new plug-in, and you can select the plug-in type and language format to be written in the plug-in template.
After clicking Create, the new plug-in just created will appear in the plug-in list.
At this time, click to open the plug-in directory, and you will find that there is a newly created plug-in folder in the originally empty plug-in directory. Right-click and use VSCode to open it.
It can be noticed that there are two files "main.lua" and "package.json" in the directory. Among them, main.lua is the entry script of the plug-in, and package.json is the configuration file of the plug-in.
After double-clicking main.lua, you can see the "onDestroy" method, and you can add subsequent cleanup code here. Save the written code and click to refresh the plug-in list in the editor to synchronize the latest plug-in code to the editor. If the editor saves at this time, if it is not a code writing error, you can refresh the plug-in by restarting the editor.
Editor's personal common API
App is the project entry class, type: CS.FairyEditor.App. The function fields in the editor can be seen through CS_FairyEditor_App in LuaAPI. The fields and methods that will be used are listed below.
CS.FairyEditor.App | ||
Field name | type | effect |
project | CS.FairyEditor.FProject | Record the configuration and resources of the current project |
libView | CS.FairyEditor.View.LibraryView | Editor's Library Panel |
inspectorView | CS.FairyEditor.View.InspectorView | Editor's Inspector panel |
consoleView | CS.FairyEditor.View.ConsoleView | Editor's console panel |
menu | CS.FairyEditor.Component.IMenu | Editor menu bar |
pluginManager | CS.FairyEditor.PluginManager | Plug-in management |
CS.FairyEditor.FProject | ||
Field name | type | effect |
name | string | Project name "such as: FGUIProject" |
basePath | string | The path of the project "such as: D:\Documents\FGUIProject" |
assetsPath | string | The path of the project "such as: D:\Documents\FGUIProject\assets" |
allPackages | CS.FairyEditor.Fpackage[] | All packages in the project |
allBranches | string[] | All branches in the project |
CS.FairyEditor.Fpackage | ||
Field name | type | effect |
name | string | The name of the current package |
items | CS.FairyEditor.FPackageItem[] | Resources under the current package |
CS.FairyEditor.FPackageItem | ||
Field name | type | effect |
path | string | Resource path |
name | string | Resource name |
CS.FairyEditor.View.LibraryView | ||
Field name | type | effect |
contextMenu | CS.FairyEditor.Component.NPopupMenu | Resource library right-click menu |
CS.FairyEditor.Component.NPopupMenu | ||
method name | parameter | effect |
AddItem | caption:string, name:string, selectCallback:(fun():void) | Add a menu item and set a selected callback event |
AddSeperator | Add menu divider | |
SetItemGrayed | string name, bool grayed | Set target cannot be clicked |
onPopup | CS.FairyGUI.EventListener | Menu popup event |
Start writing plugin code
Requirement 1
Requirement 1: Add the "Export all UI names" menu item to the tool menu, click and copy the result.
Premise: All UI interfaces have the same naming rules. Here I use UIXXX, so when getting all UIs, you only need to check whether the name of the current file UI exists. In this required function, you need to prepare a text code in Lua code format, and then replace the classField with the obtained UI name.
local tmp_ui_type = [[
---@class UIType
return {
classField
}
]]
Detailed annotations have been added to the code. You can view the complete code directly:
---@type CS.FairyEditor.App
local _app = CS.FairyEditor.App
local project = _app.project
---输出绝对文件路径
local file_out_path =("%s/UIType.lua"):format(project.basePath)
---Lua模板
local tmp_ui_type = [[
---@class UIType
return {
classField
}
]]
---获取工具菜单
---@type CS.FairyEditor.Component.MenuBar
local toolMenu = _app.menu:GetSubMenu("tool")
---添加分隔符
toolMenu:AddSeperator()
---添加菜单,显示名字,内部标签名,回调方法
toolMenu:AddItem("导出UIType","XiaoExportUIType",function()
local _classField = ""
---获取工程中的所有包,返回值是列表
local allPackages = _app.project.allPackages
for i = 1, allPackages.Count do
---C#索引从0开始
---@type CS.FairyEditor.FPackage
local package = allPackages[i - 1]
---获取当前包中的所有子项,返回值是列表
local items = package.items
for i = 1, items.Count do
---@type CS.FairyEditor.FPackageItem
local item = items[i - 1]
---记录所有UI开头的子项
if string.find(item.name,"UI") == 1 then
local uiType = string.format("%s = %s_%s,\n\t",item.name,package.name,item.name)
_classField = _classField .. uiType
end
end
end
---输出日志打印
fprint(_classField)
---替换模板
tmp_ui_type = tmp_ui_type:gsub("classField",_classField)
---写出模板
local f = io.open(file_out_path,"w")
f:write(tmp_ui_type)
f:close()
---输出路径打印
fprint(string.format("导出UIType:[url]%s[/url]",file_out_path))
end)
function onDestroy()
-------do cleanup here-------
toolMenu:RemoveItem("XiaoExportUIType")
end
Requirement 2:
Requirement 2: Add "Copy Component Script Path" to the right-click menu of the resource library to facilitate the extraction of the require path of the current component. And implement component filtering. If the conditions are not met, the "Copy Component Script Path" menu item will be grayed out and unavailable.
Prerequisite: All non-UI components are stored in the Comps folder of the current package.
Create a new plug-in or continue writing in the previous plug-in. Here I am continuing to write from the previous plug-in.
---添加资源库右键菜单
---需求:复制Comps文件夹下的组件所转化的脚本路径
---获取右键菜单
local libcontextMenu = _app.libView.contextMenu
---添加分割线
libcontextMenu:AddSeperator()
libcontextMenu:AddItem("复制组件脚本路径","XiaoCopyAssetPath",function()
---获取当前选中的资源
---@type CS.FairyEditor.FPackageItem
local item = _app.libView:GetSelectedResource()
---检测资源是否满足条件
if item.path:find("/Comps/") == 1 then
---准备复制
local cp_str = ("require(\"UI.%s.Comps.%s\")"):format(item.owner.name,item.name)
---Unity复制操作
CS.UnityEngine.GUIUtility.systemCopyBuffer = cp_str
---弹窗提示
_app.Alert("复制成功")
else
_app.Alert("复制失败")
end
end)
---在弹出的菜单中检测当前选择的资源是否满足条件
libcontextMenu.onPopup:Add(function()
---@type CS.FairyEditor.FPackageItem
local item = _app.libView:GetSelectedResource()
local grayed = true
if item.path:find("/Comps/") == 1 then
-- body
grayed = false
end
libcontextMenu:SetItemGrayed("XiaoCopyAssetPath",grayed)
end)
Don't forget to remove our menu item "XiaoCopyAssetPath" in the onDestroy method afterwards
toolMenu:RemoveItem("XiaoCopyAssetPath")
Complete plug-in code
---@type CS.FairyEditor.App
local _app = CS.FairyEditor.App
local project = _app.project
---输出绝对文件路径
local file_out_path =("%s/UIType.lua"):format(project.basePath)
---Lua模板
local tmp_ui_type = [[
---@class UIType
return {
classField
}
]]
---获取工具菜单
---@type CS.FairyEditor.Component.MenuBar
local toolMenu = _app.menu:GetSubMenu("tool")
---添加分隔符
toolMenu:AddSeperator()
---添加菜单,显示名字,内部标签名,回调方法
toolMenu:AddItem("导出UIType","XiaoExportUIType",function()
local _classField = ""
---获取工程中的所有包,返回值是列表
local allPackages = _app.project.allPackages
for i = 1, allPackages.Count do
---C#索引从0开始
---@type CS.FairyEditor.FPackage
local package = allPackages[i - 1]
---获取当前包中的所有子项,返回值是列表
local items = package.items
for i = 1, items.Count do
---@type CS.FairyEditor.FPackageItem
local item = items[i - 1]
---记录所有UI开头的子项
if string.find(item.name,"UI") == 1 then
local uiType = string.format("%s = %s_%s,\n\t",item.name,package.name,item.name)
_classField = _classField .. uiType
end
end
end
---输出日志打印
fprint(_classField)
---替换模板
tmp_ui_type = tmp_ui_type:gsub("classField",_classField)
---写出模板
local f = io.open(file_out_path,"w")
f:write(tmp_ui_type)
f:close()
---输出路径打印
fprint(string.format("导出UIType:[url]%s[/url]",file_out_path))
end)
---添加资源库右键菜单
---需求:复制Comps文件夹下的组件所转化的脚本路径
---获取右键菜单
local libcontextMenu = _app.libView.contextMenu
---添加分割线
libcontextMenu:AddSeperator()
libcontextMenu:AddItem("复制组件脚本路径","XiaoCopyAssetPath",function()
---获取当前选中的资源
---@type CS.FairyEditor.FPackageItem
local item = _app.libView:GetSelectedResource()
---检测资源是否满足条件
if item.path:find("/Comps/") == 1 then
---准备复制
local cp_str = ("require(\"UI.%s.Comps.%s\")"):format(item.owner.name,item.name)
---Unity复制操作
CS.UnityEngine.GUIUtility.systemCopyBuffer = cp_str
---弹窗提示
_app.Alert("复制成功")
else
_app.Alert("复制失败")
end
end)
---在弹出的菜单中检测当前选择的资源是否满足条件
libcontextMenu.onPopup:Add(function()
---@type CS.FairyEditor.FPackageItem
local item = _app.libView:GetSelectedResource()
local grayed = true
if item.path:find("/Comps/") == 1 then
-- body
grayed = false
end
libcontextMenu:SetItemGrayed("XiaoCopyAssetPath",grayed)
end)
function onDestroy()
-------do cleanup here-------
toolMenu:RemoveItem("XiaoExportUIType")
toolMenu:RemoveItem("XiaoCopyAssetPath")
end
Currently, only these two types of menu operations are used. If there are more in actual operations later, we will continue to update!