├── FairyGUI_GenCode_Lua ├── binder_template.txt ├── component_template.txt ├── icon.png ├── main.lua └── package.json ├── LICENSE ├── README.en.md └── README.md /FairyGUI_GenCode_Lua/binder_template.txt: -------------------------------------------------------------------------------- 1 | $requireStatement 2 | 3 | local $binderClassName = class("$binderClassName"); 4 | 5 | function $binderClassName:BindAll() 6 | $bindStatement 7 | end 8 | 9 | return $binderClassName; -------------------------------------------------------------------------------- /FairyGUI_GenCode_Lua/component_template.txt: -------------------------------------------------------------------------------- 1 | ---@class $className : $superClassName 2 | $classFieldAnnotation 3 | local $className = class("$className"); 4 | 5 | $className.URL = $urlValue; 6 | 7 | function $className:CreateInstance() 8 | self.__ui = $namespaceUIPackage.CreateObject("$uiPackageName","$uiResName"); 9 | self:OnConstruct(); 10 | return self.__ui; 11 | end 12 | 13 | function $className:OnConstruct() 14 | $classFieldInstantiation 15 | end 16 | 17 | return $className; -------------------------------------------------------------------------------- /FairyGUI_GenCode_Lua/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/northWolf/FairyGUI_GenCode_Lua/2d0b4136c793d212a3c57d9ca42214e73f7a90a5/FairyGUI_GenCode_Lua/icon.png -------------------------------------------------------------------------------- /FairyGUI_GenCode_Lua/main.lua: -------------------------------------------------------------------------------- 1 | --region LuaCodeWriter 2 | local LuaCodeWriter = fclass() 3 | 4 | function LuaCodeWriter:ctor(config) 5 | config = config or {} 6 | self.blockStart = config.blockStart or '{' 7 | self.blockEnd = config.blockEnd or '}' 8 | self.blockFromNewLine = config.blockFromNewLine 9 | if self.blockFromNewLine == nil then 10 | self.blockFromNewLine = true 11 | end 12 | if config.usingTabs then 13 | self.indentStr = '\t' 14 | else 15 | self.indentStr = ' ' 16 | end 17 | self.usingTabs = config.usingTabs 18 | self.endOfLine = config.endOfLine or '\n' 19 | self.lines = {} 20 | self.indent = 0 21 | 22 | self:writeMark() 23 | end 24 | 25 | function LuaCodeWriter:writeMark() 26 | table.insert(self.lines, '--- This is an automatically generated class by FairyGUI. Please do not modify it. ---') 27 | table.insert(self.lines, '') 28 | end 29 | 30 | function LuaCodeWriter:writeln(format, ...) 31 | if not format then 32 | table.insert(self.lines, '') 33 | return 34 | end 35 | 36 | local str = '' 37 | for i = 0, self.indent - 1 do 38 | str = str .. self.indentStr 39 | end 40 | str = str .. string.format(format, ...) 41 | table.insert(self.lines, str) 42 | 43 | return self 44 | end 45 | 46 | function LuaCodeWriter:startBlock() 47 | if self.blockFromNewLine or #self.lines == 0 then 48 | self:writeln(self.blockStart) 49 | else 50 | local str = self.lines[#self.lines] 51 | self.lines[#self.lines] = str .. ' ' .. self.blockStart 52 | end 53 | self.indent = self.indent + 1 54 | 55 | return self 56 | end 57 | 58 | function LuaCodeWriter:endBlock() 59 | self.indent = self.indent - 1 60 | self:writeln(self.blockEnd) 61 | 62 | return self 63 | end 64 | 65 | function LuaCodeWriter:incIndent() 66 | self.indent = self.indent + 1 67 | 68 | return self 69 | end 70 | 71 | function LuaCodeWriter:decIndent() 72 | self.indent = self.indent - 1 73 | 74 | return self 75 | end 76 | 77 | function LuaCodeWriter:reset() 78 | if #self.lines > 0 then 79 | self.lines = {} 80 | end 81 | self.indent = 0 82 | 83 | self:writeMark() 84 | end 85 | 86 | function LuaCodeWriter:tostring() 87 | return table.concat(self.lines, self.endOfLine) 88 | end 89 | 90 | function LuaCodeWriter:save(filePath) 91 | local str = table.concat(self.lines, self.endOfLine) 92 | 93 | CS.System.IO.File.WriteAllText(filePath, str) 94 | end 95 | 96 | --endregion 97 | 98 | local projectCustomPropertiesDic; 99 | 100 | local customPropKeys = { 101 | key_gen_lua = { name = "key_gen_lua", default_value = "true" }, 102 | key_lua_file_extension_name = { name = "key_lua_file_extension_name", default_value = "lua" }, 103 | key_lua_path_root = { name = "key_lua_path_root", default_value = "UIGenCode/" }, 104 | key_wrapper_namespace = { name = "key_wrapper_namespace", default_value = "CS.FairyGUI" }, 105 | } 106 | 107 | local function get_project_custom_property_value(key_name) 108 | if (projectCustomPropertiesDic and projectCustomPropertiesDic:ContainsKey(key_name)) then 109 | return projectCustomPropertiesDic:get_Item(key_name); 110 | else 111 | return customPropKeys[key_name].default_value; 112 | end 113 | end 114 | 115 | function onPublish(handler) 116 | if not handler.genCode or handler.publishDescOnly then 117 | return 118 | end 119 | 120 | projectCustomPropertiesDic = App.project:GetSettings("CustomProperties").elements; 121 | 122 | local gen_lua = get_project_custom_property_value(customPropKeys.key_gen_lua.name); 123 | if (gen_lua == "true") then 124 | handler.genCode = false --prevent default output 125 | App.consoleView:Clear(); 126 | fprint("Handling gen lua code in plugin.") 127 | genCode(handler) 128 | end 129 | end 130 | 131 | function genCode(handler) 132 | local settings = handler.project:GetSettings("Publish").codeGeneration 133 | local codePkgName = handler:ToFilename(handler.pkg.name); --convert chinese to pinyin, remove special chars etc. 134 | local exportCodePath = handler.exportCodePath .. '/' .. codePkgName 135 | local lua_file_extension_name = get_project_custom_property_value(customPropKeys.key_lua_file_extension_name.name); 136 | local lua_path_root = get_project_custom_property_value(customPropKeys.key_lua_path_root.name); 137 | lua_path_root = string.gsub(lua_path_root, "/", "."); 138 | lua_path_root = string.gsub(lua_path_root, "\\", "."); 139 | 140 | local namespaceName = codePkgName 141 | local key_wrapper_namespace = get_project_custom_property_value(customPropKeys.key_wrapper_namespace.name); 142 | 143 | if settings.packageName ~= nil and settings.packageName ~= '' then 144 | namespaceName = settings.packageName .. '.' .. namespaceName; 145 | end 146 | 147 | --CollectClasses(stripeMemeber, stripeClass, fguiNamespace) 148 | local classes = handler:CollectClasses(settings.ignoreNoname, settings.ignoreNoname, key_wrapper_namespace) 149 | handler:SetupCodeFolder(exportCodePath, lua_file_extension_name) --check if target folder exists, and delete old files 150 | 151 | local getMemberByName = settings.getMemberByName 152 | local classTemplateTxt = CS.System.IO.File.ReadAllText(PluginPath .. "/component_template.txt"); 153 | if (classTemplateTxt == "") then 154 | fprint("component_template.txt content null.") 155 | return ; 156 | end 157 | 158 | local classCnt = classes.Count 159 | local writer = LuaCodeWriter.new({ blockFromNewLine = false, usingTabs = true }) 160 | for i = 0, classCnt - 1 do 161 | local _classTemplateTxt = classTemplateTxt; 162 | local classInfo = classes[i] 163 | local members = classInfo.members 164 | writer:reset() 165 | 166 | _classTemplateTxt = string.gsub(_classTemplateTxt, "$className", classInfo.className); 167 | _classTemplateTxt = string.gsub(_classTemplateTxt, "$superClassName", classInfo.superClassName); 168 | if (key_wrapper_namespace ~= "") then 169 | _classTemplateTxt = string.gsub(_classTemplateTxt, "$namespace", key_wrapper_namespace .. "."); 170 | else 171 | _classTemplateTxt = string.gsub(_classTemplateTxt, "$namespace", ""); 172 | end 173 | 174 | local _classFieldAnnotation = string.format('---@field public %s %s\n', "__ui", classInfo.superClassName); 175 | local memberCnt = members.Count 176 | for j = 0, memberCnt - 1 do 177 | if (j > 0) then 178 | _classFieldAnnotation = _classFieldAnnotation .. "\n"; 179 | end 180 | local memberInfo = members[j] 181 | _classFieldAnnotation = _classFieldAnnotation .. string.format('---@field public %s %s', memberInfo.varName, memberInfo.type); 182 | end 183 | 184 | _classTemplateTxt = string.gsub(_classTemplateTxt, "$classFieldAnnotation", _classFieldAnnotation); 185 | 186 | local _urlValue = string.format('"ui://%s%s"', handler.pkg.id, classInfo.classId) 187 | _classTemplateTxt = string.gsub(_classTemplateTxt, "$urlValue", _urlValue); 188 | 189 | _classTemplateTxt = string.gsub(_classTemplateTxt, "$uiPackageName", handler.pkg.name); 190 | _classTemplateTxt = string.gsub(_classTemplateTxt, "$uiResName", classInfo.resName); 191 | 192 | local _classFieldInstatiation = ""; 193 | for j = 0, memberCnt - 1 do 194 | local memberInfo = members[j] 195 | if j > 0 then 196 | _classFieldInstatiation = _classFieldInstatiation .. "\n"; 197 | end 198 | _classFieldInstatiation = _classFieldInstatiation .. "\t"; 199 | if memberInfo.group == 0 then 200 | if getMemberByName then 201 | _classFieldInstatiation = _classFieldInstatiation .. string.format('self.%s = self.__ui:GetChild("%s");', memberInfo.varName, memberInfo.name); 202 | else 203 | _classFieldInstatiation = _classFieldInstatiation .. string.format('self.%s = self.__ui:GetChildAt("%s");', memberInfo.varName, memberInfo.index); 204 | end 205 | elseif memberInfo.group == 1 then 206 | if getMemberByName then 207 | _classFieldInstatiation = _classFieldInstatiation .. string.format('self.%s = self.__ui:GetController("%s");', memberInfo.varName, memberInfo.name); 208 | else 209 | _classFieldInstatiation = _classFieldInstatiation .. string.format('self.%s = self.__ui:GetControllerAt("%s");', memberInfo.varName, memberInfo.index); 210 | end 211 | else 212 | if getMemberByName then 213 | _classFieldInstatiation = _classFieldInstatiation .. string.format('self.%s = self.__ui:GetTransition("%s");', memberInfo.varName, memberInfo.name); 214 | else 215 | _classFieldInstatiation = _classFieldInstatiation .. string.format('self.%s = self.__ui:GetTransitionAt("%s");', memberInfo.varName, memberInfo.index); 216 | end 217 | end 218 | end 219 | _classTemplateTxt = string.gsub(_classTemplateTxt, "$classFieldInstantiation", _classFieldInstatiation); 220 | writer:writeln('%s', _classTemplateTxt); 221 | 222 | writer:save(exportCodePath .. '/' .. classInfo.className .. '.' .. lua_file_extension_name) 223 | end 224 | 225 | writer:reset() 226 | 227 | local binderTemplateTxt = CS.System.IO.File.ReadAllText(PluginPath .. "/binder_template.txt"); 228 | if (binderTemplateTxt == "") then 229 | fprint("binder_template.txt content null.") 230 | return ; 231 | end 232 | local binderName = codePkgName .. 'Binder' 233 | 234 | local _requireStatement = ""; 235 | 236 | for i = 0, classCnt - 1 do 237 | if (i > 0) then 238 | _requireStatement = _requireStatement .. "\n"; 239 | end 240 | local classInfo = classes[i] 241 | _requireStatement = _requireStatement .. string.format('%s = require("%s%s.%s");', classInfo.className, lua_path_root, codePkgName, classInfo.className); 242 | end 243 | 244 | binderTemplateTxt = string.gsub(binderTemplateTxt, "$requireStatement", _requireStatement); 245 | binderTemplateTxt = string.gsub(binderTemplateTxt, "$binderClassName", binderName); 246 | 247 | local _bindStatement = ""; 248 | for i = 0, classCnt - 1 do 249 | if (i > 0) then 250 | _bindStatement = _bindStatement .. "\n"; 251 | end 252 | local classInfo = classes[i] 253 | _bindStatement = _bindStatement .. "\t"; 254 | 255 | if (key_wrapper_namespace ~= "") then 256 | _bindStatement = _bindStatement .. string.format('%sUIObjectFactory.SetPackageItemExtension(%s.URL, typeof(%s));', key_wrapper_namespace .. ".", classInfo.className, classInfo.className); 257 | else 258 | _bindStatement = _bindStatement .. string.format('UIObjectFactory.SetPackageItemExtension(%s.URL,typeof(%s));', classInfo.className, classInfo.className); 259 | end 260 | 261 | 262 | end 263 | binderTemplateTxt = string.gsub(binderTemplateTxt, "$bindStatement", _bindStatement); 264 | writer:writeln('%s', binderTemplateTxt); 265 | writer:save(exportCodePath .. '/' .. binderName .. '.' .. lua_file_extension_name) 266 | 267 | writer:reset() 268 | 269 | local _readSuccess, _initTxt = pcall(function() 270 | return CS.System.IO.File.ReadAllText(handler.exportCodePath .. "/init.lua"); 271 | end); 272 | if(not _readSuccess) then 273 | _initTxt = ""; 274 | end 275 | local _requireStatement = string.format('local %s = require("%s%s.%s");',binderName, lua_path_root,codePkgName, binderName); 276 | _requireStatement = _requireStatement .. string.format('\n%s:BindAll();',binderName); 277 | if(string.find(_initTxt,_requireStatement,1,true) == nil) then 278 | _requireStatement = _requireStatement .. "\n"; 279 | _initTxt = _initTxt .. _requireStatement; 280 | CS.System.IO.File.WriteAllText(handler.exportCodePath .. "/init.lua", _initTxt); 281 | end 282 | end 283 | 284 | 285 | -------------------------------------------------------------------------------- /FairyGUI_GenCode_Lua/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.northwolf.plugin.gencode", 3 | "displayName": "FairyGUI GenCode Lua", 4 | "description": "Publish lua code for game engine.", 5 | "version": "1.0.0", 6 | "author": { 7 | "name": "Author: northwolf.github.io" 8 | }, 9 | "icon": "icon.png", 10 | "main": "main.lua" 11 | } 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 NOW_云端 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.en.md: -------------------------------------------------------------------------------- 1 | # FairyGUI_GenCode_Lua 2 | 3 | #### Description 4 | FairyGUI.v2020 编辑器插件,用于生成Lua视图代码绑定。 5 | 6 | #### Software Architecture 7 | Software architecture description 8 | 9 | #### Installation 10 | 11 | 1. xxxx 12 | 2. xxxx 13 | 3. xxxx 14 | 15 | #### Instructions 16 | 17 | 1. xxxx 18 | 2. xxxx 19 | 3. xxxx 20 | 21 | #### Contribution 22 | 23 | 1. Fork the repository 24 | 2. Create Feat_xxx branch 25 | 3. Commit your code 26 | 4. Create Pull Request 27 | 28 | 29 | #### Gitee Feature 30 | 31 | 1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md 32 | 2. Gitee blog [blog.gitee.com](https://blog.gitee.com) 33 | 3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore) 34 | 4. The most valuable open source project [GVP](https://gitee.com/gvp) 35 | 5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help) 36 | 6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FairyGUI_GenCode_Lua 2 | 3 | #### 介绍 4 | FairyGUI.v2020 编辑器插件,用于生成 Lua UI绑定代码。 5 | 6 | #### 安装教程 7 | 8 | 克隆本项目到 FairyGUI 工程的 plugins 目录中,刷新 FairyGUI 编辑器插件窗口或重启编辑器。 9 | 10 | #### 使用说明 11 | 12 | 1. 本项目理论上适用使用 Lua 作为UI逻辑的游戏引擎,但只在 Unity 引擎下进行了测试。 13 | 2. 使用本插件前,需要先熟悉编辑器发布代码的功能,并开启发布代码。 14 | 3. 使用 编辑器—项目设置—自定义属性 为插件功能赋值。 15 | ``` 16 | local customPropKeys = { 17 | key_gen_lua = { name = "key_gen_lua", default_value = "true" }, 18 | key_lua_file_extension_name = { name = "key_lua_file_extension_name", default_value = "lua" }, 19 | key_lua_path_root = { name = "key_lua_path_root", default_value = "UIGenCode/" }, 20 | key_wrapper_namespace = { name = "key_wrapper_namespace", default_value = "" }, 21 | } 22 | ``` 23 | * key_gen_lua 是否生成Lua代码,默认为值 true 24 | * key_lua_file_extension_name Lua文件的扩展名,默认值为 lua 25 | * key_lua_path_root 生成文件相对于Lua执行根路径的相对路径,默认值为 UIGenCode/ 26 | * key_wrapper_namespace 框架层 FairyGUI 导出代码的命名空间,默认值为 CS.FairyGUI 27 | 28 | 4. 生成文件是根据模板文件 __component_template.txt__ 和 __binder_template.txt__ 生成,以 __$XXX__ 作为占位符,可以在此基础上继续自定义扩展。 29 | 5. 使用生成文件示例: 30 | ``` 31 | require("UIGenCode.init"); 32 | UI_DemoComponent:CreateInstance(); 33 | GRoot.inst:AddChild(UI_DemoComponent.__ui); 34 | UI_DemoComponent.m_btn_login.onClick:Add(function() 35 | print("btn clicked"); 36 | end); 37 | ``` 38 | * 绑定类是自动调用绑定方法的,只需要引入一次 init.lua 文件即可。 39 | * 为了使用方便,生成的组件类都是全局名称,这一点需要注意。如果不需要生成全局名称,则修改插件源码。 40 | * 组件实例默认赋值为 __ui 对象,为了防止被组件子级覆盖,使用了双下划线命名。 41 | * 不要手动修改生成文件,以免被下一次生成覆盖,更好的办法是修改插件源码和模板文件。 42 | 6. 本项目参考了官方的 [GenCode](https://github.com/fairygui/FairyGUI-Editor) 插件,作为补充,提供Lua生成作为一个选项。 43 | --------------------------------------------------------------------------------