在FGUI中可以自己去写lua的插件,来实现各种功能,最近写了一个自动生成UI控件的插件,需要的自取
总共分为4个文件,全部放在FGUI的工程目录下的plugins文件夹里
CodeGenEntry.lua
CodeGenConfig.lua
HotfixCodeGenHandler.lua
package.json
package.json
{
"name": "CodeGenerate",
"displayName": "代码生成插件",
"description": "",
"version": "0.0.1",
"author": {
"name": "meta404"
},
"icon": "icon.png",
"main": "CodeGenEntry.lua"
}
CodeGenEntry.lua
local CodeGenEntry = {}
---@type HotfixCodeGenHandler
CodeGenEntry.HotfixCodeGenHandler = require(PluginPath .. '/HotfixCodeGenHandler')
---@type CodeGenConfig
CodeGenEntry.CodeGenConfig = require(PluginPath .. "/CodeGenConfig")
--- 点击发布工程时的回调
---@param handler CS.FairyEditor.PublishHandler 发布处理者
function onPublish(handler)
--- 不勾选生成代码时,将为其生成热更层代码
if not handler.genCode then
CodeGenEntry.HotfixCodeGenHandler.Do(handler, CodeGenEntry.CodeGenConfig)
else
--- 勾选生成代码时,将为其生成非热更层代码
CodeGenEntry.ModelCodeGenHandler.Do(handler, CodeGenEntry.CodeGenConfig)
end
end
return CodeGenEntry
CodeGenConfig.lua
---@class CodeGenConfig 代码生成配置
local GenerateHotfixCodeConfig = {
--- 热更代码配置
--- 热更层命名空间
HotfixNameSpace = "HotfixUI",
--- 热更层代码输出目录
--HotfixCodeOutPutPath = "../Unity/Assets/ModelView/Demo/FGUI/AutoGeneratedCode/",
HotfixCodeOutPutPath = "E:/Project/Red/SVN/RedWar/Projects/RedWar/HotUpdateScripts/Game/UI/AutoGeneratedCode/",
--- 代码裁剪,即是否为默认名称对象生成获取代码,如果为true,代表不会生成,否则会生成,注意如果开启可能会导致需要导出的类也没有导出的情况
CodeStrip = false,
--- 组件名前缀
ClassNamePrefix = "FUI_",
--- 成员名前缀
MemerVarNamePrefix = "m_"
}
return GenerateHotfixCodeConfig
HotfixCodeGenHandler.lua
---@class HotfixCodeGenHandler 热更层代码生成器
local HotfixCodeGenHandler = {}
--- 执行生成热更层代码
---@param handler CS.FairyEditor.PublishHandler
---@param codeGenConfig CodeGenConfig
function HotfixCodeGenHandler.Do(handler, codeGenConfig)
fprint("开始生成Hotfix代码")
local codePkgName = handler:ToFilename(handler.pkg.name); --convert chinese to pinyin, remove special chars etc.
--- 从自定义配置中读取路径和命名空间
local exportCodePath = codeGenConfig.HotfixCodeOutPutPath .. '/' .. codePkgName
local namespaceName = codeGenConfig.HotfixNameSpace
--- 初始化自定义组件名前缀
local classNamePrefix = codeGenConfig.ClassNamePrefix
--- 初始化自定义成员变量名前缀
local memberVarNamePrefix = codeGenConfig.MemerVarNamePrefix
--- 从FGUI编辑器中读取配置
---@type CS.FairyEditor.GlobalPublishSettings.CodeGenerationConfig
local settings = handler.project:GetSettings("Publish").codeGeneration
local getMemberByName = settings.getMemberByName
--- 所有将要导出的类(当前包的所有设置为导出的组件,以及当前包所有被引用的组件)
---@type CS.FairyEditor.PublishHandler.ClassInfo[]
local classes = handler:CollectClasses(codeGenConfig.CodeStrip, codeGenConfig.CodeStrip, nil)
handler:SetupCodeFolder(exportCodePath, "cs") --check if target folder exists, and delete old files
fprint("找到" .. classes.Count .. "个classes的数量")
local classCnt = classes.Count
local writer = CodeWriter.new()
local mainPanelIndex = 0
for i = 0, classCnt - 1 do
local className = classes[i].className
fprint("class name: " .. className)
if(string.find(className, 'Panel') ~= nil) then
mainPanelIndex = i
break;
end
end
--for i = 0, classCnt - 1 do
for i = mainPanelIndex, mainPanelIndex do
local classInfo = classes[i]
local members = classInfo.members
writer:reset()
writer:writeln('/** ============================================================================== **/')
writer:writeln('/** ============================Auto Generate Class=============================== **/')
writer:writeln('/** ============================================================================== **/')
writer:writeln()
writer:writeln('using FairyGUI;')
writer:writeln('using FUIFW;')
writer:writeln()
writer:writeln('namespace %s', namespaceName)
writer:startBlock()
--- 组装自定义组件前缀
local className = classNamePrefix .. classInfo.className
writer:writeln([[public partial class %s : FUIBase
{
]], codePkgName, codePkgName, classInfo.resName, classInfo.superClassName)
local memberCnt = members.Count
fprint("找到了" .. memberCnt .. " 个成员变量")
-- 是否为自定义类型组件标记数组
local customComponentFlagsArray = {}
-- 是否为跨包组件标记数组
local crossPackageFlagsArray = {}
for j = 0, memberCnt - 1
do
local memberInfo = members[j]
customComponentFlagsArray[j] = false
crossPackageFlagsArray[j] = false
-- 判断是不是我们自定义类型组件
local typeName = memberInfo.type
for k = 0, classCnt - 1
do
if typeName == classes[k].className
then
typeName = classNamePrefix .. classes[k].className
customComponentFlagsArray[j] = true
break
end
end
-- 判断是不是跨包类型组件
if memberInfo.res ~= nil then
--- 组装自定义组件前缀
typeName = classNamePrefix .. memberInfo.res.name
crossPackageFlagsArray[j] = true
end
--- 组装自定义成员前缀
writer:writeln('\tpublic %s %s;', typeName, memberVarNamePrefix .. memberInfo.varName)
end
writer:writeln()
writer:writeln([[
public void Init(GObject go)
{
if(go == null)
{
return;
}
var com = go.asCom;
if(com != null)
{
]], classInfo.superClassName)
for j = 0, memberCnt - 1
do
local memberInfo = members[j]
--- 组装自定义成员前缀
local memberVarName = memberVarNamePrefix .. memberInfo.varName
if memberInfo.group == 0
then
if getMemberByName
then
if customComponentFlagsArray[j]
then
--- 组装自定义组件前缀
writer:writeln('\t\t\t%s = new %s(com.GetChildAt(%s));', memberVarName, classNamePrefix .. memberInfo.type, memberInfo.name)
elseif crossPackageFlagsArray[j]
then
--- 组装自定义组件前缀
writer:writeln('\t\t\t%s = new %s(com.GetChildAt(%s));', memberVarName, classNamePrefix .. memberInfo.res.name, memberInfo.name)
else
writer:writeln('\t\t\t%s = (%s)com.GetChild("%s");', memberVarName, memberInfo.type, memberInfo.name)
end
else
if customComponentFlagsArray[j]
then
--- 组装自定义组件前缀
writer:writeln('\t\t\t%s = new %s(com.GetChildAt(%s));', memberVarName, classNamePrefix .. memberInfo.type, memberInfo.index)
elseif crossPackageFlagsArray[j]
then
--- 组装自定义组件前缀
writer:writeln('\t\t\t%s = new %s(com.GetChildAt(%s));', memberVarName, classNamePrefix .. memberInfo.res.name, memberInfo.index)
else
writer:writeln('\t\t\t%s = (%s)com.GetChildAt(%s);', memberVarName, memberInfo.type, memberInfo.index)
end
end
elseif memberInfo.group == 1
then
if getMemberByName
then
writer:writeln('\t\t\t%s = com.GetController("%s");', memberVarName, memberInfo.name)
else
writer:writeln('\t\t\t%s = com.GetControllerAt(%s);', memberVarName, memberInfo.index)
end
else
if getMemberByName
then
writer:writeln('\t\t\t%s = com.GetTransition("%s");', memberVarName, memberInfo.name)
else
writer:writeln('\t\t\t%s = com.GetTransitionAt(%s);', memberVarName, memberInfo.index)
end
end
end
writer:writeln('\t\t}')
writer:writeln('\t}')
writer:writeln()
local classCntSub = classes.Count
fprint('找到了' .. classCntSub - 1 .. '个子对象')
for m = 0, classCntSub - 1 do
if(m ~= mainPanelIndex) then
local classInfoSub = classes[m]
local membersSub = classInfoSub.members
local classNameSub = classNamePrefix .. classInfoSub.className
writer:writeln([[
public class %s
{
]], classNameSub)
local memberCntSub = membersSub.Count
-- 是否为自定义类型组件标记数组
local customComponentFlagsArraySub = {}
-- 是否为跨包组件标记数组
local crossPackageFlagsArraySub = {}
for n = 0, memberCntSub - 1
do
local memberInfoSub = membersSub[n]
customComponentFlagsArraySub[n] = false
crossPackageFlagsArraySub[n] = false
-- 判断是不是我们自定义类型组件
local typeNameSub = memberInfoSub.type
for k = 0, classCntSub - 1
do
if typeNameSub == classes[m].className
then
typeNameSub = classNamePrefix .. classes[m].className
customComponentFlagsArraySub[n] = true
break
end
end
-- 判断是不是跨包类型组件
if memberInfoSub.res ~= nil then
--- 组装自定义组件前缀
typeNameSub = classNamePrefix .. memberInfoSub.res.name
crossPackageFlagsArraySub[n] = true
end
--- 组装自定义成员前缀
writer:writeln('\t\tpublic %s %s;', typeNameSub, memberVarNamePrefix .. memberInfoSub.varName)
end
writer:writeln()
writer:writeln([[
public %s(GObject go)
{
if(go == null)
{
return;
}
var com = go.asCom;
if(com != null)
{
]], classNameSub)
for j = 0, memberCntSub - 1
do
local memberInfoSub = membersSub[j]
--- 组装自定义成员前缀
local memberVarNameSub = memberVarNamePrefix .. memberInfoSub.varName
if memberInfoSub.group == 0
then
if getMemberByNameSub
then
if customComponentFlagsArraySub[j]
then
--- 组装自定义组件前缀
writer:writeln('\t\t\t\t%s = new %s(com.GetChildAt(%s));', memberVarNameSub, classNamePrefix .. memberInfoSub.type, memberInfoSub.name)
elseif crossPackageFlagsArraySub[j]
then
--- 组装自定义组件前缀
writer:writeln('\t\t\t\t%s = new %s(com.GetChildAt(%s));', memberVarNameSub, classNamePrefix .. memberInfoSub.res.name, memberInfoSub.name)
else
writer:writeln('\t\t\t\t%s = (%s)com.GetChild("%s");', memberVarNameSub, memberInfoSub.type, memberInfoSub.name)
end
else
if customComponentFlagsArraySub[j]
then
--- 组装自定义组件前缀
writer:writeln('\t\t\t\t%s = new %s(com.GetChildAt(%s));', memberVarNameSub, classNamePrefix .. memberInfoSub.type, memberInfoSub.index)
elseif crossPackageFlagsArraySub[j]
then
--- 组装自定义组件前缀
writer:writeln('\t\t\t\t%s = new %s(com.GetChildAt(%s));', memberVarNameSub, classNamePrefix .. memberInfoSub.res.name, memberInfoSub.index)
else
writer:writeln('\t\t\t\t%s = (%s)com.GetChildAt(%s);', memberVarNameSub, memberInfoSub.type, memberInfoSub.index)
end
end
elseif memberInfoSub.group == 1
then
if getMemberByNameSub
then
writer:writeln('\t\t\t\t%s = com.GetController("%s");', memberVarNameSub, memberInfoSub.name)
else
writer:writeln('\t\t\t\t%s = com.GetControllerAt(%s);', memberVarNameSub, memberInfoSub.index)
end
else
if getMemberByNameSub
then
writer:writeln('\t\t\t\t%s = com.GetTransition("%s");', memberVarNameSub, memberInfoSub.name)
else
writer:writeln('\t\t\t\t%s = com.GetTransitionAt(%s);', memberVarNameSub, memberInfoSub.index)
end
end
end
writer:writeln('\t\t\t}')
writer:writeln('\t\t}')
writer:writeln('\t}')
writer:writeln()
end
end
writer:writeln('}')
writer:endBlock()
path = exportCodePath .. '/' .. codePkgName .. '.cs'
writer:save(path)
fprint("生成代码完毕:" .. path)
end
end
return HotfixCodeGenHandler
最后看下生成的效果
/** This is an automatically generated class by FairyGUI. Please do not modify it. **/
/** ============================================================================== **/
/** ============================Auto Generate Class=============================== **/
/** ============================================================================== **/
using FairyGUI;
using FUIFW;
namespace HotfixUI
{
public partial class UI_ThisIsExample : FUIBase
{
public GList m_list_Labels;
public GGraph m_graph_Mask;
public GTextField m_text_Exa;
public FUI_Clone m_clone_Test;
public FUI_Label1 m_label_t;
public void Init(GObject go)
{
if(go == null)
{
return;
}
var com = go.asCom;
if(com != null)
{
m_list_Labels = (GList)com.GetChildAt(0);
m_graph_Mask = (GGraph)com.GetChildAt(1);
m_text_Exa = (GTextField)com.GetChildAt(2);
m_clone_Test = new FUI_Clone(com.GetChildAt(3));
m_label_t = new FUI_Label1(com.GetChildAt(4));
}
}
public class FUI_Label1
{
public GTextField m_title;
public FUI_Label1(GObject go)
{
if(go == null)
{
return;
}
var com = go.asCom;
if(com != null)
{
m_title = (GTextField)com.GetChildAt(0);
}
}
}
public class FUI_Button1
{
public Controller m_button;
public GGraph m_n0;
public GGraph m_n1;
public GGraph m_n2;
public FUI_Button1(GObject go)
{
if(go == null)
{
return;
}
var com = go.asCom;
if(com != null)
{
m_button = com.GetControllerAt(0);
m_n0 = (GGraph)com.GetChildAt(0);
m_n1 = (GGraph)com.GetChildAt(1);
m_n2 = (GGraph)com.GetChildAt(2);
}
}
}
public class FUI_Clone
{
public GTextField m_text_Content;
public FUI_Clone(GObject go)
{
if(go == null)
{
return;
}
var com = go.asCom;
if(com != null)
{
m_text_Content = (GTextField)com.GetChildAt(0);
}
}
}
}
}