import FairyGUI = CS.FairyGUI; import FairyEditor = CS.FairyEditor; import System = CS.System; import CodeWriter, { ICodeWriterConfig } from './CodeWriter'; import genSetting, { ComponentData, MemberData } from './GenCodeSettings' import languageSetting, { LanguageComponentChildData } from './LanguageSettings' const File = System.IO.File; const Directory = System.IO.Directory; const App = FairyEditor.App; var allSuperClassNameByUrl = {} var allCustomNameByUrl = {} var namespaceName = ""; var setNamespaceName = false var exportCodePath = "" var existScriptPaths = {}; var packageName = '' //获取所有的文件的路径 function getAllDirector(path: string, list: Array) { let dirs = Directory.GetDirectories(path) for (let index = 0; index < dirs.Length; index++) { let dir = dirs.get_Item(index); getAllFile(dir, list) let dirs2 = Directory.GetDirectories(dir) if (dirs2.Length > 0) { getAllDirector(dir, list) } } } function getAllFile(dir: string, list: Array) { let files = Directory.GetFiles(dir, "*.cs") for (let f = 0; f < files.Length; f++) { list.push(files.get_Item(f)) } } class WhootCodeWriterConfig implements ICodeWriterConfig { blockStart?: string; blockEnd?: string; blockFromNewLine?: boolean; usingTabs?: boolean; endOfLine?: string; fileMark?: string; } function genCSCode(handler: FairyEditor.PublishHandler) { console.log("gencode==========--------------========") let settings = (handler.project.GetSettings("Publish")).codeGeneration; let codePkgName = handler.ToFilename(handler.pkg.name); exportCodePath = handler.exportCodePath // + '/' + codePkgName; console.log("exportCodePath=", exportCodePath) let pkgId = handler.pkg.id; packageName = handler.pkg.name existScriptPaths = {}; let list: Array = [] getAllFile(exportCodePath, list) //开始前,先遍历整个生成目录。找寻所有文件。用以判断生成的文件存放地址 getAllDirector(exportCodePath, list); for (let index = 0; index < list.length; index++) { let path = list[index]; var newPath = path.replace(/\\/g, '/'); let arrs = newPath.split('/') let key = arrs[arrs.length - 1] existScriptPaths[key] = path } namespaceName = ""; setNamespaceName = false if (settings.packageName) { namespaceName = settings.packageName setNamespaceName = true } let classes = handler.CollectClasses(settings.ignoreNoname, settings.ignoreNoname, null); let getMemberByName = true;//默认使用名称获取对象//settings.getMemberByName; console.log(codePkgName, namespaceName, getMemberByName) let classCnt = classes.Count; allCustomNameByUrl = {} allSuperClassNameByUrl = {} let dependPackages: Array = [] //因为没有文档,同时返回内容限制,先保存子类基类关系。用于后续判断是否使用自定义类 for (let i: number = 0; i < classCnt; i++) { let classInfo = classes.get_Item(i); let url = classInfo.res.GetURL(); allSuperClassNameByUrl[url] = classInfo.superClassName let config: ComponentData = genSetting.getComponentSetting(url) if (config != null) { if (config.isCustomName) { allCustomNameByUrl[url] = settings.classNamePrefix + config.customName } } //获取依赖的包 for (let index = 0; index < classInfo.members.Count; index++) { let element = classInfo.members.get_Item(index); if (element.res != null && element.res.owner != null) { let pname = element.res.owner.name; if (dependPackages.indexOf(pname) < 0 && pname != codePkgName) { dependPackages.push(pname) } } } } let componentClassNameArr: Array = [] for (let i: number = 0; i < classCnt; i++) { let classInfo = classes.get_Item(i); let url = classInfo.res.GetURL(); let config: ComponentData = genSetting.getComponentSetting(url) if (config != null) { console.log(config.name, config.scriptType) if (config.scriptType == "panel") { genPanelCode(classInfo, config, codePkgName, pkgId, dependPackages); } else if (config.scriptType == "component") { let ComponentClassName = genComponentCode(classInfo, config, codePkgName, pkgId) componentClassNameArr.push(ComponentClassName) } } else { console.log(classInfo.resName + "未配置导出,忽略") } } console.log("生成Binder,count="+componentClassNameArr.length) genBinder(codePkgName, componentClassNameArr); genLanguage(); } function getScriptName(className: string, comUrl: string) { if (allCustomNameByUrl.hasOwnProperty(comUrl)) { className = allCustomNameByUrl[comUrl] } return className } function genPanelCode(classInfo: FairyEditor.PublishHandler.ClassInfo, config: ComponentData, codePkgName: string, pkgId: string, dependPackages?: Array) { let codeConfig: WhootCodeWriterConfig = new WhootCodeWriterConfig(); codeConfig.fileMark = "/**本脚本为自动生成,每次生成会覆盖!请勿手动修改,生成插件文档及项目地址:https://git.whoot.com/whoot-games/whoot.fguieditorplugin**/" let comUrl = classInfo.res.GetURL(); //先生成 .Designer部分 let writer = new CodeWriter(codeConfig); writer.writeln('using FairyGUI;'); writer.writeln('using FairyGUI.Utils;'); writer.writeln('using NBC;'); writer.writeln('using System.Collections.Generic;'); writer.writeln(); let className = getScriptName(classInfo.className, comUrl) if (setNamespaceName) { writer.writeln('namespace %s', namespaceName); writer.startBlock(); writer.writeln("/// %s ", config.annotation); writer.writeln('public partial class %s', className); writer.startBlock(); } else { writer.writeln("/// %s ", config.annotation); writer.writeln('public partial class %s', className); writer.startBlock(); } writer.writeln("public GObject this[string aKey] => ContentPane.GetChild(aKey);"); let members = classInfo.members; let memberCnt = members.Count for (let j: number = 0; j < memberCnt; j++) { let memberInfo = members.get_Item(j); if (memberInfo.res != null) { let superClassName = getComponentUseClassName(memberInfo, comUrl) writer.writeln('[AutoFind(Name = "%s")]', memberInfo.name) //判断配置,是否需要使用生成的类 writer.writeln('public %s %s;', superClassName, memberInfo.varName); } else { writer.writeln('[AutoFind(Name = "%s")]', memberInfo.name) writer.writeln('public %s %s;', memberInfo.type, memberInfo.varName); } } let url = `ui://${pkgId}${classInfo.resId}` if (dependPackages != null) { let str = ""; let len = dependPackages.length - 1; for (let index = 0; index <= len; index++) { let pname = dependPackages[index]; str += `"${pname}"`; if (index < len) { str += ","; } } writer.writeln(`public override string[] GetDependPackages(){ return new string[] {${str}}; }`) writer.writeln(); } writer.writeln(); writer.endBlock(); if (setNamespaceName) { writer.endBlock(); } let fileName = className + ".Designer" + '.cs' let savePath = exportCodePath + '/' + fileName if (existScriptPaths.hasOwnProperty(fileName)) { console.log("脚本已经有同名的,替换地址=", fileName, existScriptPaths[fileName]) savePath = existScriptPaths[fileName] } writer.save(savePath); // 判断模块脚本是否存在。如果不存在,创建默认模板脚本 let defFileName = className + '.cs' if (!existScriptPaths.hasOwnProperty(defFileName)) { let mainSavePath = exportCodePath + '/' + defFileName console.log("Panel的主脚本不存在,生成默认=", mainSavePath) writer.reset(); codeConfig.fileMark = "// 本脚本只在不存在时会生成一次。已存在不会再次生成覆盖" writer = new CodeWriter(codeConfig); writer.writeln('using UnityEngine;'); writer.writeln('using NBC;'); writer.writeln(); if (setNamespaceName) { writer.writeln('namespace %s', namespaceName); writer.startBlock(); writer.writeln('public partial class %s : UIPanel', className); writer.startBlock(); } else { writer.writeln('public partial class %s : UIPanel', className); writer.startBlock(); } writer.writeln('public override string UIPackName => "%s";', codePkgName); writer.writeln('public override string UIResName => "%s";', classInfo.res.name); writer.writeln(); writer.writeln('protected override void OnInit()'); writer.startBlock(); writer.writeln('base.OnInit();'); writer.endBlock(); writer.writeln(); writer.writeln('protected override void OnShow()'); writer.startBlock(); writer.writeln('base.OnShow();'); writer.endBlock(); writer.writeln(); writer.writeln('protected override void OnHide()'); writer.startBlock(); writer.writeln('base.OnHide();'); writer.endBlock(); writer.writeln(); writer.writeln('protected override void OnDestroy()'); writer.startBlock(); writer.writeln('base.OnDestroy();'); writer.endBlock(); writer.endBlock(); if (setNamespaceName) { writer.endBlock(); } writer.save(mainSavePath); } } function getComponentUseClassName(memberInfo: FairyEditor.PublishHandler.MemberInfo, comUrl: string) { let name = memberInfo.type let useCustomScript = false if (memberInfo.res != null) { let comUrl = memberInfo.res.GetURL(); //是自定义组件,改为使用原生,不适用自定义 let superClassName = allSuperClassNameByUrl[comUrl] let config: ComponentData = genSetting.getComponentSetting(comUrl) if (config != null && config.scriptType == "component") { superClassName = memberInfo.res.name useCustomScript = true } if (superClassName == null || superClassName == undefined) { superClassName = memberInfo.type } name = superClassName } return name;//{ name: name, useCustomScript: useCustomScript } } function genComponentCode(classInfo: FairyEditor.PublishHandler.ClassInfo, config: ComponentData, codePkgName: string, pkgId: string) { let codeConfig: WhootCodeWriterConfig = new WhootCodeWriterConfig(); codeConfig.fileMark = "/**本脚本为自动生成,每次生成会覆盖!请勿手动修改,生成插件文档及项目地址:https://git.whoot.com/whoot-games/whoot.fguieditorplugin**/" let comUrl = classInfo.res.GetURL(); let className = getScriptName(classInfo.className, comUrl) let writer = new CodeWriter(codeConfig); writer.writeln(); writer.writeln('using FairyGUI;'); writer.writeln('using FairyGUI.Utils;'); writer.writeln('using NBC;'); writer.writeln(); if (setNamespaceName) { writer.writeln('namespace %s', namespaceName); writer.startBlock(); writer.writeln('public partial class %s', className); writer.startBlock(); } else { writer.writeln('public partial class %s', className); writer.startBlock(); } writer.writeln('public const string URL = "ui://%s%s";', pkgId, classInfo.resId); writer.writeln(); //生成成员变量 let members = classInfo.members; let memberCnt = members.Count for (let j: number = 0; j < memberCnt; j++) { let memberInfo = members.get_Item(j); if (memberInfo.res != null) { let superClassName = getComponentUseClassName(memberInfo, comUrl) writer.writeln('public %s %s;', superClassName, memberInfo.varName); } else { writer.writeln('public %s %s;', memberInfo.type, memberInfo.varName); } } writer.writeln(); writer.writeln('public override void ConstructFromXML(XML xml)'); writer.startBlock(); writer.writeln('base.ConstructFromXML(xml);'); writer.writeln(); for (let j: number = 0; j < memberCnt; j++) { let memberInfo = members.get_Item(j); if (memberInfo.group == 0) { let superClassName = memberInfo.type let useExtend = false if (memberInfo.res != null) { superClassName = getComponentUseClassName(memberInfo, comUrl) } writer.writeln('%s = (%s)GetChild("%s");', memberInfo.varName, superClassName, memberInfo.name); } else if (memberInfo.group == 1) { writer.writeln('%s = GetController("%s");', memberInfo.varName, memberInfo.name); } else { writer.writeln('%s = GetTransition("%s");', memberInfo.varName, memberInfo.name); } } writer.writeln('OnInited();'); writer.writeln('UILanguage.TrySetComponentLanguage(this);'); writer.endBlock(); writer.endBlock(); if (setNamespaceName) { writer.endBlock(); } let fileName = className + ".Designer" + '.cs' let savePath = exportCodePath + '/' + fileName if (existScriptPaths.hasOwnProperty(fileName)) { console.log("脚本已经有同名的,替换地址=", fileName, existScriptPaths[fileName]) savePath = existScriptPaths[fileName] } writer.save(savePath); // 判断模块脚本是否存在。如果不存在,创建默认模板脚本 let defFileName = className + '.cs' if (!existScriptPaths.hasOwnProperty(defFileName)) { let mainSavePath = exportCodePath + '/' + defFileName console.log("Component的主脚本不存在,生成默认") writer.reset(); codeConfig.fileMark = "// 本脚本只在不存在时会生成一次。组件逻辑写在当前脚本内。已存在不会再次生成覆盖 " writer = new CodeWriter(codeConfig); writer.writeln('using UnityEngine;'); writer.writeln('using FairyGUI;'); writer.writeln('using NBC;'); writer.writeln(); if (setNamespaceName) { writer.writeln('namespace %s', namespaceName); writer.startBlock(); writer.writeln('public partial class %s : %s', className, classInfo.superClassName); writer.startBlock(); } else { writer.writeln('public partial class %s : %s', className, classInfo.superClassName); writer.startBlock(); } writer.writeln('private void OnInited()'); writer.startBlock(); writer.endBlock(); writer.endBlock(); if (setNamespaceName) { writer.endBlock(); } writer.save(mainSavePath); } return className } /** * 生成自定义脚本绑定关系 * @param codePkgName * @param componentClassNameArr */ function genBinder(codePkgName: string, componentClassNameArr: Array) { let binderName = codePkgName + 'Binder'; let codeConfig: WhootCodeWriterConfig = new WhootCodeWriterConfig(); codeConfig.fileMark = "/**注册组件绑定关系。本脚本为自动生成,每次生成会覆盖!请勿手动修改,生成插件文档及项目地址:https://git.whoot.com/whoot-games/whoot.fguieditorplugin**/" let writer = new CodeWriter(codeConfig); writer.reset(); writer.writeln('using FairyGUI;'); writer.writeln(); if (setNamespaceName) { writer.writeln('namespace %s', namespaceName); writer.startBlock(); } writer.writeln('public class %s', binderName); writer.startBlock(); writer.writeln('public static void BindAll()'); writer.startBlock(); for (let i: number = 0; i < componentClassNameArr.length; i++) { //let classInfo = classes.get_Item(i); let name = componentClassNameArr[i] writer.writeln('UIObjectFactory.SetPackageItemExtension(%s.URL, typeof(%s));', name, name); } writer.endBlock(); //bindall writer.endBlock(); //class if (setNamespaceName) { writer.endBlock(); //namespace } let fileName = binderName + '.cs' let savePath = exportCodePath + '/' + fileName console.log("生成binder 1=", fileName) if (existScriptPaths.hasOwnProperty(fileName)) { savePath = existScriptPaths[fileName] } writer.save(savePath); } /** * 生成多语言 */ function genLanguage() { let binderName = 'UILangeageConfig'; let languageMap = languageSetting.getAllPackage() //getPackage let codeConfig: WhootCodeWriterConfig = new WhootCodeWriterConfig(); codeConfig.fileMark = "/**注册组件多语言绑定。本脚本为自动生成,每次生成会覆盖!请勿手动修改,生成插件文档及项目地址:https://git.whoot.com/whoot-games/whoot.fguieditorplugin**/" let writer = new CodeWriter(codeConfig); writer.reset(); writer.writeln('using System.Collections.Generic;'); writer.writeln('using FairyGUI;'); writer.writeln('using NBC;'); writer.writeln(); if (setNamespaceName) { writer.writeln('namespace %s', namespaceName); writer.startBlock(); } writer.writeln('public class %s : UIComponentLanguagePack', binderName); writer.startBlock(); writer.writeln('public UILangeageConfig()'); writer.startBlock(); writer.writeln('AddData();'); writer.endBlock(); writer.writeln('private void AddData()'); writer.startBlock(); let keys = languageMap.keys(); for (let key of keys) { let pack = languageMap.get(key); let languageData = pack.components; for (let comUrl in languageData) { let comObj = languageData[comUrl]; if (comObj == undefined) continue; writer.writeln('Add("%s", new UIComponentLanguage()', comUrl); writer.startBlock(); for (let key2 in comObj) { var cfg = comObj[key2] let useable = cfg['useable'] let languageKey = cfg["key"] if (useable != 1) continue; writer.writeln('{ "%s", "%s" },', key2, languageKey); } writer.endBlock(); writer.writeln(');'); } writer.writeln(); } // for (let comUrl in languageData) { // let comObj = languageData[comUrl]; // if (comObj != undefined) { // for (let key in comObj) { // var cfg = comObj[key] // let useable = cfg['useable'] // let languageKey = cfg["key"] // if (useable == 1) { // console.log("comurl:" + comUrl + " key:" + key + " lan:" + languageKey) // } // } // } // } writer.endBlock(); //bindall writer.endBlock(); //class if (setNamespaceName) { writer.endBlock(); //namespace } let fileName = binderName + '.cs' let savePath = exportCodePath + '/' + fileName console.log("生成 language=", fileName) if (existScriptPaths.hasOwnProperty(fileName)) { savePath = existScriptPaths[fileName] } writer.save(savePath); } export { genCSCode };