using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using Convention; using UnityEngine; namespace Demo.Editor { public static class ProjectCreateHelper { private static string GetTypename(Type type) { string result = type.Name; if (result.Contains('`')) return result[..result.LastIndexOf('`')]; return result; } private static void WritePythonStyleFunction(StreamWriter stream, string name, IEnumerable paramList, string description) { stream.Write($"def {name}({string.Join(',', paramList)}):\n"); stream.Write($"'''\n{description}\n'''\n...\n\n"); } private static void WriteCPPClassBase(StreamWriter stream, Type currentType) { string currentTypeName = GetTypename(currentType); string baseTypeName = GetTypename(currentType.BaseType); if (currentType == typeof(ScriptableObject)) { // 绘制工具宏 stream.WriteLine("#define __build_in_pragma #"); stream.WriteLine("#define __build_in_to_text(x) #x"); stream.WriteLine("#define this"); // 绘制类定义标识符 foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) { foreach (var type in asm.GetTypes()) { // Functions if (typeof(ScriptableObject).IsAssignableFrom(type)) { string typeName = GetTypename(type); stream.WriteLine($"#define {typeName} \"{typeName}\""); } } } // 绘制Mathf foreach (var method in typeof(Mathf).GetMethods()) { stream.WriteLine($"#define {method.Name}({string.Join(',', from param in method.GetParameters() select param.Name)})"); } foreach (var curveType in Enum.GetNames(typeof(MathExtension.EaseCurveType))) { stream.WriteLine($"#define {curveType}"); } // 绘制RScript关键词 { stream.Write(@" /* 控制流标签 */ "); stream.Write($"#define label(label_name) __build_in_pragma define label_name\n\n"); } { stream.Write(@" /* 控制流, 当pr为真时跳转到指定的label处 */ "); stream.Write($"#define goto(pr,label_name)\n\n"); } { stream.Write(@" /* 控制流, 当pr为真时返回上一次调用goto的位置, 栈模式 */ "); stream.Write($"#define back(pr)\n\n"); } { stream.Write(@" /* 控制流, 当pr为真时退出当前命名空间 */ "); stream.Write($"#define break(pr)\n\n"); } { stream.Write(@" /* 赋名命名空间, 具有名称的命名空间将不会自动运行, 需要使用goto到达 */ "); stream.Write($"#define namespace(name)\n\n"); } stream.WriteLine($"struct {currentTypeName}"); stream.WriteLine("{"); } else { stream.Write($"#include \"{baseTypeName}.helper.h\"\n\n"); stream.WriteLine($"struct {currentTypeName}:public {baseTypeName}"); stream.WriteLine("{"); } } private static void WriteCPPStyleFunction(StreamWriter stream, string name, IEnumerable paramList, string description) { if (name == nameof(ScriptableObject.LoadSubScript)) { stream.Write("/*\n" + description + "\n*/\n"); stream.Write($"#define {name}({string.Join(',', paramList)}) __build_in_pragma include {paramList.ToArray()[1]}\n\n"); //stream.Write($"#define {name}({string.Join(',', paramList)})\n\n"); } else { stream.Write("/*\n" + description + "\n*/\n"); stream.Write($"#define {name}({string.Join(',', paramList)}) \n\n"); } } private static void WriteCPPClassEnd(StreamWriter stream, Type currentType) { stream.WriteLine("};"); } public static void CreateHelperFiles(string dir, ProjectDefaultFileStyle style = ProjectDefaultFileStyle.CPP) { var toolDir = new ToolFile(dir); if (toolDir.IsDir() == false) { throw new InvalidOperationException("Not a directory"); } toolDir.MustExistsPath(); foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) { foreach (var type in asm.GetTypes()) { // Functions if (typeof(ScriptableObject).IsAssignableFrom(type)) { var scriptCalls = (from info in type.GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly) where info is MethodInfo where info.GetCustomAttribute(false) != null select info as MethodInfo).ToList(); var typeName = GetTypename(type); string fileHeader = $"{typeName}.helper" + style switch { ProjectDefaultFileStyle.PY => ",py", _ => ".h" }; using var fs = File.AppendText((toolDir | fileHeader).GetFullPath()); switch (style) { case ProjectDefaultFileStyle.CPP: WriteCPPClassBase(fs, type); break; case ProjectDefaultFileStyle.PY: break; } foreach (var methodInfo in scriptCalls) { var data = methodInfo.GetCustomAttribute(false); switch (style) { case ProjectDefaultFileStyle.PY: WritePythonStyleFunction(fs, methodInfo.Name, from param in methodInfo.GetParameters() select param.Name, data.Description); break; default: WriteCPPStyleFunction(fs, methodInfo.Name, from param in methodInfo.GetParameters() select param.Name, data.Description); break; } } switch (style) { case ProjectDefaultFileStyle.CPP: WriteCPPClassEnd(fs, type); break; case ProjectDefaultFileStyle.PY: break; } } // Enums if (typeof(Enum).IsAssignableFrom(type)&& type.GetCustomAttribute(false) != null) { // TODO } } } } } }