You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

683 lines
26 KiB

import { FairyEditor, System } from "csharp";
import { CodeGenConfig } from "./CodeGenConfig";
import CodeWriter from "./CodeWriter";
import { normalCodeGenerator } from "./NormalCodeGenerator";
class FUICodeGenerator
{
private settings;
private codePkgName;
private classes: System.Collections.Generic.List$1<FairyEditor.PublishHandler.ClassInfo>;
private handler: FairyEditor.PublishHandler;
// save path
private hotfixViewExportCodePath: string;
private modelViewExportCodePath: string;
private hotfixViewLogicExportCodePath: string;
private modelViewLogicExportCodePath: string;
// 动态加载的Item的类生成路径
private itemClassExportCodePath: string;
public Handle(handler: FairyEditor.PublishHandler)
{
let settings = (<FairyEditor.GlobalPublishSettings>handler.project.GetSettings("Publish")).codeGeneration;
let codePkgName = handler.ToFilename(handler.pkg.name); //convert chinese to pinyin, remove special chars etc.
this.settings = settings;
this.codePkgName = codePkgName;
this.handler = handler;
// 从自定义配置中读取路径和命名空间
this.hotfixViewExportCodePath = CodeGenConfig.HotfixViewCodeOutputPath + '/' + codePkgName;
this.modelViewExportCodePath = CodeGenConfig.ModelViewCodeOutputPath + '/' + codePkgName;
this.hotfixViewLogicExportCodePath = CodeGenConfig.HotfixViewLogicCodeOutputPath + "/" + codePkgName;
this.modelViewLogicExportCodePath = CodeGenConfig.ModelViewLogicCodeOutputPath + "/" + codePkgName;
this.itemClassExportCodePath = CodeGenConfig.ModelViewCodeOutputPath + '/' + codePkgName;
//CollectClasses(stripeMember, stripeClass, fguiNamespace)
let classes = handler.CollectClasses(settings.ignoreNoname, settings.ignoreNoname, null);
this.classes = classes;
handler.SetupCodeFolder(this.hotfixViewExportCodePath, "cs"); //check if target folder exists, and delete old files
handler.SetupCodeFolder(this.modelViewExportCodePath, "cs"); //check if target folder exists, and delete old files
let classCnt = classes.Count;
let codeWriter = new CodeWriter();
for (let i: number = 0; i < classCnt; i++) {
let classInfo = classes.get_Item(i);
// 是否为自定义类型组件标记数组
let customComponentFlagsArray = []
// 是否为跨包组件标记数组
let crossPackageFlagsArray = []
this.generateModelViewCode(classInfo, codeWriter, customComponentFlagsArray, crossPackageFlagsArray);
this.generateHotfixViewCode(classInfo, codeWriter, customComponentFlagsArray, crossPackageFlagsArray);
this.generateLogicCode(classInfo, codeWriter, customComponentFlagsArray, crossPackageFlagsArray);
this.generateItemCode(classInfo, codeWriter);
}
}
// 判断是不是我们自定义类型组件
private isCustomClass(typeName: string)
{
let classes = this.classes;
let count = this.classes.Count
for (let k = 0; k < count; k++)
{
if (typeName === classes.get_Item(k).className)
{
return true;
}
}
return false;
}
private getCustomClassName(className: string)
{
return CodeGenConfig.ClassNamePrefix + className;
}
private generateModelViewCode(classInfo: FairyEditor.PublishHandler.ClassInfo, modelViewCodeWriter: CodeWriter, customComponentFlagsArray: boolean[], crossPackageFlagsArray: boolean[])
{
let codePkgName = this.codePkgName;
let modelViewExportCodePath = this.modelViewExportCodePath;
let namespaceName = CodeGenConfig.ModelViewNameSpace;
// 初始化自定义成员变量名前缀
let memberVarNamePrefix = CodeGenConfig.MemberVarNamePrefix;
// 组装自定义组件前缀
let className = this.getCustomClassName(classInfo.className);
let members = classInfo.members;
modelViewCodeWriter.reset();
modelViewCodeWriter.writeln('using FairyGUI;');
modelViewCodeWriter.writeln();
modelViewCodeWriter.writeln('namespace %s', namespaceName);
modelViewCodeWriter.startBlock();
// pakage namespace
modelViewCodeWriter.writeln('namespace %s', CodeGenConfig.NameSpacePrefix + codePkgName);
modelViewCodeWriter.startBlock();
// 用const 在ILRuntime中的反射获取Field会得不到值,所以改用static
modelViewCodeWriter.writeln(`[ComponentOf(typeof(FUI))]
public sealed class %s : Entity, IAwake, IDestroy
{
public static string UIPackageName = "%s";
public static string UIResName = "%s";
/// <summary>
/// {uiResName}的组件类型(GComponent、GButton、GProcessBar等),它们都是GObject的子类。
/// </summary>
public %s FGComp;
`, className, codePkgName, classInfo.resName, classInfo.superClassName);
let memberCnt = members.Count
for (let j: number = 0; j < memberCnt; j++) {
let memberInfo = members.get_Item(j);
customComponentFlagsArray[j] = false;
crossPackageFlagsArray[j] = false;
// 判断是不是我们自定义类型组件
let typeName = memberInfo.type;
if (this.isCustomClass(typeName))
{
typeName = this.getCustomClassName(typeName);
customComponentFlagsArray[j] = true;
}
// 判断是不是跨包类型组件
if (memberInfo && memberInfo.res)
{
// 组装自定义组件前缀
typeName = this.getCustomClassName(memberInfo.res.name);
crossPackageFlagsArray[j] = true;
}
// 组装自定义成员前缀
modelViewCodeWriter.writeln('\tpublic %s %s;', typeName, memberVarNamePrefix + memberInfo.varName);
}
modelViewCodeWriter.writeln('\tpublic const string URL = "ui://%s%s";', this.handler.pkg.id, classInfo.resId);
modelViewCodeWriter.writeln();
// modelViewCodeWriter.writeln(`
// public override void Dispose()
// {
// if(IsDisposed)
// {
// return;
// }
// base.Dispose();
// FGComp.Remove();
// FGComp = null;
// `)
// for (let j = 0; j < memberCnt; j++)
// {
// let memberInfo = members.get_Item(j);
// // 组装自定义成员前缀
// let memberVarName = memberVarNamePrefix + memberInfo.varName;
// if (memberInfo.group === 0)
// {
// if (customComponentFlagsArray[j] || crossPackageFlagsArray[j])
// {
// modelViewCodeWriter.writeln('\t\t%s.Dispose();', memberVarName)
// }
// }
// modelViewCodeWriter.writeln('\t\t%s = null;', memberVarName)
// }
// modelViewCodeWriter.writeln('\t}');
modelViewCodeWriter.writeln(`
public bool Visible
{
get
{
if (FGComp == null)
{
return false;
}
return FGComp.visible;
}
set
{
if (FGComp == null)
{
return;
}
FGComp.visible = value;
}
}`
);
modelViewCodeWriter.writeln('}');
modelViewCodeWriter.endBlock(); // package namespace
modelViewCodeWriter.endBlock(); // topmost namespace
modelViewCodeWriter.save(modelViewExportCodePath + '/' + className + '.cs');
/////////////////
// 写入fuipackage
/////////////////
modelViewCodeWriter.reset();
modelViewCodeWriter.writeln('namespace %s', namespaceName);
modelViewCodeWriter.startBlock();
modelViewCodeWriter.writeln('public static partial class FUIPackage');
modelViewCodeWriter.startBlock();
modelViewCodeWriter.writeln('public const string %s = "%s";', codePkgName, codePkgName);
for(let i = 0; i < this.classes.Count; i++)
{
let classInfo = this.classes.get_Item(i);
modelViewCodeWriter.writeln('public const string %s_%s = "ui://%s/%s";', codePkgName, classInfo.resName, codePkgName, classInfo.resName);
}
modelViewCodeWriter.endBlock(); // class
modelViewCodeWriter.endBlock();
let binderPackageName = 'Package' + codePkgName;
modelViewCodeWriter.save(modelViewExportCodePath + '/' + binderPackageName + '.cs');
}
private generateHotfixViewCode(classInfo: FairyEditor.PublishHandler.ClassInfo, hotfixViewCodeWriter: CodeWriter, customComponentFlagsArray: boolean[], crossPackageFlagsArray: boolean[])
{
let hotfixViewExportCodePath = this.hotfixViewExportCodePath;
let namespaceName = CodeGenConfig.HotfixViewNameSpace;
let getMemberByName = this.settings.getMemberByName;
// 初始化自定义组件名前缀
let classNamePrefix = CodeGenConfig.ClassNamePrefix;
// 初始化自定义成员变量名前缀
let memberVarNamePrefix = CodeGenConfig.MemberVarNamePrefix;
// 组装自定义组件前缀
let className = this.getCustomClassName(classInfo.className);
let systemName = className + "System";
let members = classInfo.members;
hotfixViewCodeWriter.reset();
hotfixViewCodeWriter.writeln('using FairyGUI;');
hotfixViewCodeWriter.writeln('using System.Threading.Tasks;');
hotfixViewCodeWriter.writeln();
hotfixViewCodeWriter.writeln('namespace %s', namespaceName);
hotfixViewCodeWriter.startBlock();
hotfixViewCodeWriter.writeln('namespace %s', CodeGenConfig.NameSpacePrefix + this.codePkgName);
hotfixViewCodeWriter.startBlock();
// writer.writeln('public partial class %s : %s', classInfo.className, classInfo.superClassName);
// writer.startBlock();
// awake system
hotfixViewCodeWriter.writeln(
`public class %sAwakeSystem : AwakeSystem<%s>
{
public override void Awake(%s self)
{
self.Awake();
}
}
`, className, className, className);
// destroy system
hotfixViewCodeWriter.writeln(
`public class %sDestroySystem : DestroySystem<%s>
{
public override void Destroy(%s self)
{
self.Destroy();
}
}
`, className, className, className);
hotfixViewCodeWriter.writeln('[FriendClass(typeof(FUI))]');
hotfixViewCodeWriter.writeln(`[FriendClass(typeof(%s))]`, className);
// add component system
hotfixViewCodeWriter.writeln(`public static class %s
{`, systemName);
hotfixViewCodeWriter.writeln(`
public static void Awake(this %s self)
{
var fui = self.GetParent<FUI>();
if(fui.GObject == null)
{
return;
}
self.FGComp = (%s)fui.GObject;
self.FGComp.Add(fui);
var com = fui.GObject.asCom;
if(com != null)
{
`,className, classInfo.superClassName);
let memberCnt = members.Count
for(let j = 0; j < memberCnt; j++)
{
let memberInfo = members.get_Item(j);
// 组装自定义成员前缀
let memberVarName = memberVarNamePrefix + memberInfo.varName;
if (memberInfo.group === 0)
{
if (getMemberByName)
{
if (customComponentFlagsArray[j])
{
// 组装自定义组件前缀
hotfixViewCodeWriter.writeln('\t\t\tself.%s = FUIHelper.Create<%s>(self, com.GetChild("%s"));', memberVarName, this.getCustomClassName(memberInfo.type), memberInfo.name);
}
else if(crossPackageFlagsArray[j])
{
// 组装自定义组件前缀
hotfixViewCodeWriter.writeln('\t\t\tself.%s = FUIHelper.Create<%s>(self, com.GetChild("%s"));', memberVarName,this.getCustomClassName(memberInfo.res.name), memberInfo.name);
}
else
{
hotfixViewCodeWriter.writeln('\t\t\tself.%s = (%s)com.GetChild("%s");', memberVarName, memberInfo.type, memberInfo.name);
}
}
else
{
if (customComponentFlagsArray[j])
{
// 组装自定义组件前缀
hotfixViewCodeWriter.writeln('\t\t\tself.%s = FUIHelper.Create<%s>(self, com.GetChildAt(%s));', memberVarName,this.getCustomClassName(memberInfo.type), memberInfo.index);
}
else if(crossPackageFlagsArray[j])
{
// 组装自定义组件前缀
hotfixViewCodeWriter.writeln('\t\t\tself.%s = FUIHelper.Create<%s>(self, com.GetChildAt(%s));', memberVarName, this.getCustomClassName(memberInfo.res.name), memberInfo.index);
}
else
{
hotfixViewCodeWriter.writeln('\t\t\tself.%s = (%s)com.GetChildAt(%s);', memberVarName, memberInfo.type, memberInfo.index);
}
}
}
else if (memberInfo.group == 1)
{
if (getMemberByName)
{
hotfixViewCodeWriter.writeln('\t\t\tself.%s = com.GetController("%s");', memberVarName, memberInfo.name)
}
else
{
hotfixViewCodeWriter.writeln('\t\t\tself.%s = com.GetControllerAt(%s);', memberVarName, memberInfo.index)
}
}
else
{
if (getMemberByName)
{
hotfixViewCodeWriter.writeln('\t\t\tself.%s = com.GetTransition("%s");', memberVarName, memberInfo.name)
}
else
{
hotfixViewCodeWriter.writeln('\t\t\tself.%s = com.GetTransitionAt(%s);', memberVarName, memberInfo.index)
}
}
}
hotfixViewCodeWriter.writeln('\t\t}') // end of if
hotfixViewCodeWriter.writeln('\t}') // end of awake function
hotfixViewCodeWriter.writeln(`
public static void Destroy(this %s self)
{
if(self.IsDisposed)
{
return;
}
self.FGComp.Remove();
self.FGComp = null;
`, className);
for (let j = 0; j < memberCnt; j++)
{
let memberInfo = members.get_Item(j);
// 组装自定义成员前缀
let memberVarName = memberVarNamePrefix + memberInfo.varName;
if (memberInfo.group === 0)
{
if (customComponentFlagsArray[j] || crossPackageFlagsArray[j])
{
hotfixViewCodeWriter.writeln('\t\tself.%s.Dispose();', memberVarName)
}
}
hotfixViewCodeWriter.writeln('\t\tself.%s = null;', memberVarName)
}
hotfixViewCodeWriter.writeln('\t}') // end of Destroy function
hotfixViewCodeWriter.writeln('}');
hotfixViewCodeWriter.endBlock(); // package namespace
hotfixViewCodeWriter.endBlock(); // topmost namespace
hotfixViewCodeWriter.save(hotfixViewExportCodePath + '/' + className + '.cs');
}
private isBanAutoGenerateClass(className: string)
{
return CodeGenConfig.BanClassOfAutoGenerate.includes(className);
}
private generateLogicCode(classInfo: FairyEditor.PublishHandler.ClassInfo, logicCodeWriter: CodeWriter, customComponentFlagsArray: boolean[], crossPackageFlagsArray: boolean[])
{
// 只关注需要导出的类
if (classInfo.res.exported && !this.needGenCompClass(classInfo.className))
{
let modelViewLogicExportCodePath = this.modelViewLogicExportCodePath;
let hotfixViewLogicExportCodePath = this.hotfixViewLogicExportCodePath;
let namespaceName = CodeGenConfig.ModelViewNameSpace;
let classNamePrefix = CodeGenConfig.ClassNamePrefix;
let compClassName = classNamePrefix + classInfo.className;
let compPropName = "FUI"+classInfo.className;
let logicClassNamePrefix = CodeGenConfig.LogicClassNamePrefix;
let logicComponentClassName = logicClassNamePrefix + classInfo.className + "Component";
let logicSystemClassName = logicComponentClassName + "System";
let logicComponentClassFilePath = modelViewLogicExportCodePath + "/" + logicComponentClassName + '.cs';
let logicSystemClassFilePath = hotfixViewLogicExportCodePath + "/" + logicSystemClassName + '.cs';
// 生成打FriendClass的Attribute的partial类
let friendClassCodePath = this.hotfixViewExportCodePath + "/" + "Friend";
let friendClassFilePath = friendClassCodePath + "/" + logicSystemClassName + 'Friend.cs';
if (!System.IO.Directory.Exists(friendClassCodePath))
{
System.IO.Directory.CreateDirectory(friendClassCodePath);
}
logicCodeWriter.reset();
logicCodeWriter.writeln('namespace %s', namespaceName);
logicCodeWriter.startBlock();
logicCodeWriter.writeln('using %s;', CodeGenConfig.NameSpacePrefix + this.codePkgName);
let members = classInfo.members;
let memberCnt = members.Count
for(let j = 0; j < memberCnt; j++)
{
let memberInfo = members.get_Item(j);
if (memberInfo.group === 0)
{
if ((customComponentFlagsArray[j] || crossPackageFlagsArray[j]))
{
logicCodeWriter.writeln(`[FriendClass(typeof(%s))]`,this.getCustomClassName(memberInfo.type));
}
}
}
if(!this.isBanAutoGenerateClass(classInfo.className))
{
logicCodeWriter.writeln(`
[FriendClass(typeof(%s))]`
, logicComponentClassName);
}
logicCodeWriter.writeln(`
[FriendClass(typeof(%s))]`
, compClassName);
logicCodeWriter.writeln(`
public static partial class %s
{
}
`, logicSystemClassName);
logicCodeWriter.endBlock(); // end of namespace
logicCodeWriter.save(friendClassFilePath);
let isWindow = false;
if (classInfo.className.endsWith("Window"))
{
isWindow = true;
}
if (!System.IO.Directory.Exists(modelViewLogicExportCodePath))
{
System.IO.Directory.CreateDirectory(modelViewLogicExportCodePath);
}
// 生成Component代码
if (!System.IO.File.Exists(logicComponentClassFilePath) && !this.isBanAutoGenerateClass(classInfo.className)) {
logicCodeWriter.reset();
logicCodeWriter.writeln('namespace %s', namespaceName);
logicCodeWriter.startBlock();
logicCodeWriter.writeln('using %s;', CodeGenConfig.NameSpacePrefix + this.codePkgName);
if (isWindow) {
logicCodeWriter.writeln('using FairyGUI;');
logicCodeWriter.writeln(`
public class %s : Entity, IAwake, IDestroy, IFUIWindow
{
public Window Window { get; set; }
public %s %s;
}
`, logicComponentClassName, compClassName, compPropName);
} else
{
logicCodeWriter.writeln(`
public class %s : Entity, IAwake, IDestroy
{
public %s %s;
}
`, logicComponentClassName, compClassName, compPropName);
}
logicCodeWriter.endBlock();
logicCodeWriter.save(logicComponentClassFilePath);
}
if (!System.IO.Directory.Exists(hotfixViewLogicExportCodePath))
{
System.IO.Directory.CreateDirectory(hotfixViewLogicExportCodePath);
}
// 生成System代码
if (!System.IO.File.Exists(logicSystemClassFilePath) && !this.isBanAutoGenerateClass(classInfo.className)) {
let logicAwakeSystemName = logicComponentClassName + "AwakeSystem";
logicCodeWriter.reset();
if (isWindow)
{
logicCodeWriter.writeln('using FairyGUI;');
}
logicCodeWriter.writeln('namespace %s', namespaceName);
logicCodeWriter.startBlock();
logicCodeWriter.writeln('using %s;', CodeGenConfig.NameSpacePrefix + this.codePkgName);
logicCodeWriter.writeln(`
public class %s : AwakeSystem<%s>
{
public override void Awake(%s self)
{
self.Awake();
}
}
`, logicAwakeSystemName, logicComponentClassName, logicComponentClassName);
if (isWindow)
{
logicCodeWriter.writeln(`
public static partial class %s
{
public static void Awake(this %s self)
{
self.%s = self.Parent.GetComponent<%s>();
self.Window = new Window();
self.Window.contentPane = self.%s.FGComp;
}
}
`,logicSystemClassName, logicComponentClassName, compPropName, compClassName, compPropName);
} else {
logicCodeWriter.writeln(`
public static partial class %s
{
public static void Awake(this %s self)
{
self.%s = self.Parent.GetComponent<%s>();
}
}
`,logicSystemClassName, logicComponentClassName, compPropName, compClassName);
}
logicCodeWriter.endBlock();
logicCodeWriter.save(logicSystemClassFilePath);
}
}
}
private needGenCompClass(className: string) : boolean
{
if (className.endsWith("Item")|| className.endsWith("CheckBox"))
{
return true;
}
return false;
}
private generateItemCode(classInfo: FairyEditor.PublishHandler.ClassInfo, writer: CodeWriter)
{
// 只关注需要导出的类
if (classInfo.res.exported)
{
if (!this.needGenCompClass(classInfo.className))
{
return;
}
let getMemberByName = this.settings.getMemberByName;
let className = classInfo.className;
let members = classInfo.members;
writer.reset();
writer.writeln('using FairyGUI;');
writer.writeln('using FairyGUI.Utils;');
writer.writeln();
writer.writeln('namespace %s', CodeGenConfig.ModelViewNameSpace);
writer.startBlock();
writer.writeln('namespace %s', CodeGenConfig.NameSpacePrefix + this.codePkgName);
writer.startBlock();
writer.writeln('public partial class %s : %s', className, classInfo.superClassName);
writer.startBlock();
let memberCnt = members.Count
for (let j: number = 0; j < memberCnt; j++) {
let memberInfo = members.get_Item(j);
let memberType = memberInfo.type;
let typeName = memberType;
writer.writeln('public %s %s;', typeName, memberInfo.varName);
}
writer.writeln('public const string URL = "ui://%s%s";', this.handler.pkg.id, classInfo.resId);
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 memberType = memberInfo.type;
let typeName = memberType;
if (getMemberByName)
writer.writeln('%s = (%s)GetChild("%s");', memberInfo.varName, typeName, memberInfo.name);
else
writer.writeln('%s = (%s)GetChildAt(%s);', memberInfo.varName, typeName, memberInfo.index);
}
else if (memberInfo.group == 1) {
if (getMemberByName)
writer.writeln('%s = GetController("%s");', memberInfo.varName, memberInfo.name);
else
writer.writeln('%s = GetControllerAt(%s);', memberInfo.varName, memberInfo.index);
}
else {
if (getMemberByName)
writer.writeln('%s = GetTransition("%s");', memberInfo.varName, memberInfo.name);
else
writer.writeln('%s = GetTransitionAt(%s);', memberInfo.varName, memberInfo.index);
}
}
writer.endBlock();
writer.endBlock(); // class
writer.endBlock(); // sub namespace
writer.endBlock(); // root namespace
writer.save(this.itemClassExportCodePath + '/' + className + '.cs');
}
}
}
const fuiCodeGenerator = new FUICodeGenerator();
export { fuiCodeGenerator }