/// <summary> /// Generate new Atoms based on the input data. /// </summary> /// <param name="valueType">The type of Atom to generate.abstract Eg. double, byte, MyStruct, MyClass.</param> /// <param name="baseWritePath">Base write path (relative to the Asset folder) where the Atoms are going to be written to.</param> /// <param name="isEquatable">Is the `type` provided implementing `IEquatable`?</param> /// <param name="atomTypesToGenerate">A list of `AtomType`s to be generated.</param> /// <param name="typeNamespace">If the `type` provided is defined under a namespace, provide that namespace here.</param> /// <param name="subUnityAtomsNamespace">By default the Atoms that gets generated will be under the namespace `UnityAtoms`. If you for example like it to be under `UnityAtoms.MyNamespace` you would then enter `MyNamespace` in this field.</param> /// <example> /// <code> /// namespace MyNamespace /// { /// public struct MyStruct /// { /// public string Text; /// public int Number; /// } /// } /// var generator = new Generator(); /// generator.Generate("MyStruct", "", false, new List<AtomType>() { AtomTypes.ACTION }, "MyNamespace", ""); // Generates an Atom Action of type MyStruct /// </code> /// </example> public static void Generate(AtomReceipe atomReceipe, string baseWritePath, string[] templatePaths, List <string> templateConditions, Dictionary <string, string> templateVariables) { var(atomType, valueType) = atomReceipe; // TODO: More validation of that the type exists / is correct. if (string.IsNullOrEmpty(valueType)) { Debug.LogWarning($"{Runtime.Constants.LOG_PREFIX} You need to specify a value type. Aborting!"); return; } if (string.IsNullOrEmpty(baseWritePath) || !Directory.Exists(baseWritePath)) { Debug.LogWarning($"{Runtime.Constants.LOG_PREFIX} You need to specify a valid base write path. Aborting!"); return; } Debug.Log($"{Runtime.Constants.LOG_PREFIX} Generating atom {atomType.Name} for value type {valueType}"); List <Tuple <string, string> > filesToGenerate = new List <Tuple <string, string> >() { new Tuple <string, string>(atomType.TemplateName, atomType.RelativeFileNameAndPath) }; if (atomType.HasDrawerTemplate) { filesToGenerate.Add(new Tuple <string, string>(atomType.DrawerTemplateName, atomType.RelativeDrawerFileNameAndPath)); } if (atomType.HasEditorTemplate) { filesToGenerate.Add(new Tuple <string, string>(atomType.EditorTemplateName, atomType.RelativeEditorFileNameAndPath)); } foreach (var(templateName, relativeFilePath) in filesToGenerate) { var templatePath = templatePaths.FirstOrDefault((path) => path.EndsWith(templateName)); if (string.IsNullOrEmpty(templatePath)) { Debug.Log($"{Runtime.Constants.LOG_PREFIX} Template {templateName} for {atomType.DisplayName} not found. Skipping!"); return; } var resolvedRelativeFilePath = Templating.ResolveVariables(templateVariables: templateVariables, toResolve: relativeFilePath); var template = File.ReadAllText(templatePath); var filePath = Path.Combine(baseWritePath, resolvedRelativeFilePath); var fileDirectory = Path.GetDirectoryName(filePath); // Create write directory Directory.CreateDirectory(fileDirectory); // Adjust content var content = Templating.ResolveVariables(templateVariables: templateVariables, toResolve: template); content = Templating.ResolveConditionals(template: content, trueConditions: templateConditions); content = RemoveDuplicateNamespaces(template: content); // Write to file File.WriteAllText(filePath, content); AssetDatabase.ImportAsset(filePath); } }
/// <summary> /// Resolve file name based on input data. /// </summary> /// <param name="templateVariables">Template variables. </param> /// <param name="templateName">Template name.</param> /// <param name="lastIndexOfDoubleUnderscore">Last index of double underscore.</param> /// <param name="capitalizedType">Capitalized type.</param> /// <param name="capitalizedAtomType">Capitalized Atom type (string).</param> /// <param name="typeOccurrences">Number of occurrences of the type.</param> /// <returns>The filename to use.</returns> private static string ResolveFileName(Dictionary <string, string> templateVariables, string templateName, int lastIndexOfDoubleUnderscore, string capitalizedType, string capitalizedAtomType, int typeOccurrences) { if (templateName.Contains("Set{TYPE_NAME}VariableValue")) { return(Templating.ResolveVariables(templateVariables: templateVariables, toResolve: $"{capitalizedAtomType}.cs")); } string fileName; if (templateName.Contains("AtomDrawer")) { fileName = $"{capitalizedType.Repeat(typeOccurrences)}{capitalizedAtomType}Drawer.cs"; } else if (templateName.Contains("AtomEditor")) { fileName = $"{capitalizedType.Repeat(typeOccurrences)}{capitalizedAtomType}Editor.cs"; } else { fileName = $"{capitalizedType.Repeat(typeOccurrences)}{capitalizedAtomType}.cs"; } return(Templating.ResolveVariables(templateVariables: templateVariables, toResolve: fileName)); }
/// <summary> /// Generate new Atoms based on the input data. /// </summary> /// <param name="type">The type of Atom to generate.abstract Eg. double, byte, MyStruct, MyClass.</param> /// <param name="baseWritePath">Base write path (relative to the Asset folder) where the Atoms are going to be written to.</param> /// <param name="isEquatable">Is the `type` provided implementing `IEquatable`?</param> /// <param name="atomTypesToGenerate">A list of `AtomType`s to be generated.</param> /// <param name="typeNamespace">If the `type` provided is defined under a namespace, provide that namespace here.</param> /// <param name="subUnityAtomsNamespace">By default the Atoms that gets generated will be under the namespace `UnityAtoms`. If you for example like it to be under `UnityAtoms.MyNamespace` you would then enter `MyNamespace` in this field.</param> /// <example> /// <code> /// namespace MyNamespace /// { /// public struct MyStruct /// { /// public string Text; /// public int Number; /// } /// } /// var generator = new Generator(); /// generator.Generate("MyStruct", "", false, new List<AtomType>() { AtomTypes.ACTION }, "MyNamespace", ""); // Generates an Atom Action of type MyStruct /// </code> /// </example> public void Generate(string type, string baseWritePath, bool isEquatable, List <AtomType> atomTypesToGenerate, string typeNamespace, string subUnityAtomsNamespace) { // TODO: More validation of that the type exists / is correct. if (string.IsNullOrEmpty(type)) { Debug.LogWarning($"{Runtime.Constants.LOG_PREFIX} You need to specify a type name. Aborting!"); return; } if (string.IsNullOrEmpty(baseWritePath)) { Debug.LogWarning($"{Runtime.Constants.LOG_PREFIX} You need to specify a write path. Aborting!"); return; } Debug.Log($"{Runtime.Constants.LOG_PREFIX} Generating " + type); // Create directories in path if they don't exists Directory.CreateDirectory(baseWritePath); // Recursively search for template files. TODO: Is there a better way to find and load templates? var templateSearchPath = Runtime.IsUnityAtomsRepo ? Directory.GetParent(Directory.GetParent(Application.dataPath).FullName).FullName : Directory.GetParent(Application.dataPath).FullName; var templatePaths = Directory.GetFiles(templateSearchPath, "UA_Template*.txt", SearchOption.AllDirectories); var templateConditions = new List <string>(); if (isEquatable) { templateConditions.Add("EQUATABLE"); } if (!string.IsNullOrEmpty(typeNamespace)) { templateConditions.Add("TYPE_HAS_NAMESPACE"); } if (!string.IsNullOrEmpty(subUnityAtomsNamespace)) { templateConditions.Add("HAS_SUB_UA_NAMESPACE"); } var capitalizedType = Capitalize(type); var templateVariables = new Dictionary <string, string>() { { "TYPE_NAME", capitalizedType }, { "TYPE", type } }; if (!string.IsNullOrEmpty(typeNamespace)) { templateVariables.Add("TYPE_NAMESPACE", typeNamespace); } if (!string.IsNullOrEmpty(subUnityAtomsNamespace)) { templateVariables.Add("SUB_UA_NAMESPACE", subUnityAtomsNamespace); } foreach (var templatePath in templatePaths) { var templateNameStartIndex = templatePath.LastIndexOf(Path.DirectorySeparatorChar) + 1; var fileExtLength = 4; var templateName = templatePath.Substring(templateNameStartIndex, templatePath.Length - templateNameStartIndex - fileExtLength); var lastIndexOfDoubleUnderscore = templateName.LastIndexOf("__"); var atomType = templateName.Substring(lastIndexOfDoubleUnderscore + 2); var capitalizedAtomType = Capitalize(atomType); var typeOccurrences = templateName.Substring(lastIndexOfDoubleUnderscore - 1, 1).ToInt(def: 1); if (ShouldSkipTemplate(atomTypesToGenerate, capitalizedAtomType, typeOccurrences)) { continue; } var template = File.ReadAllText(templatePath); // Create write directory var dirPath = ResolveDirPath(baseWritePath, capitalizedAtomType, templateName, atomType); Directory.CreateDirectory(dirPath); // Adjust content var content = Templating.ResolveVariables(templateVariables: templateVariables, toResolve: template); content = Templating.ResolveConditionals(template: content, trueConditions: templateConditions); content = RemoveDuplicateNamespaces(content); // Write to file var fileName = ResolveFileName(templateVariables, templateName, lastIndexOfDoubleUnderscore, capitalizedType, capitalizedAtomType, typeOccurrences); var filePath = Path.Combine(dirPath, fileName); File.WriteAllText(filePath, content); AssetDatabase.ImportAsset(filePath); } AssetDatabase.Refresh(); }
public void Generate() { var type = Type.GetType($"{FullQualifiedName}"); if (type == null) { throw new TypeLoadException($"Type could not be found ({FullQualifiedName})"); } var isValueTypeEquatable = type.GetInterfaces().Contains(typeof(IEquatable <>)); var templateVariables = Generator.CreateTemplateVariablesMap(BaseType, Namespace, "BaseAtoms"); var capitalizedValueType = BaseType.Capitalize(); var templates = Generator.GetTemplatePaths(); var templateConditions = Generator.CreateTemplateConditions(isValueTypeEquatable, Namespace, "BaseAtoms", BaseType); var baseWritePath = Path.Combine((Path.GetDirectoryName(AssetDatabase.GetAssetPath(this.GetInstanceID()))) ?? "Assets/", "Generated"); Directory.CreateDirectory(baseWritePath); Scripts.Clear(); var t = GenerationOptions; var idx = 0; while (t > 0) { if (t % 2 == 1) { var atomType = AtomTypes.ALL_ATOM_TYPES[idx]; templateVariables["VALUE_TYPE_NAME"] = atomType.IsValuePair ? $"{capitalizedValueType}Pair" : capitalizedValueType; var valueType = atomType.IsValuePair ? $"{capitalizedValueType}Pair" : BaseType; templateVariables["VALUE_TYPE"] = valueType; var resolvedRelativeFilePath = Templating.ResolveVariables(templateVariables: templateVariables, toResolve: atomType.RelativeFileNameAndPath); var targetPath = Path.Combine(baseWritePath, resolvedRelativeFilePath); var newCreated = !File.Exists(targetPath); Generator.Generate(new AtomReceipe(atomType, valueType), baseWritePath, templates, templateConditions, templateVariables); if (newCreated) { AssetDatabase.ImportAsset(targetPath); } var ms = AssetDatabase.LoadAssetAtPath <MonoScript>(targetPath); Scripts.Add(ms); } else { Scripts.Add(null); } idx++; t >>= 1; } }