void ICustomVisit <UTinyEntity.Reference> .CustomVisit(UTinyEntity.Reference value) { int index; if (Property.Name == "parent" && m_Container is UTinyObject.PropertiesContainer && ((UTinyObject.PropertiesContainer)m_Container).ParentObject.Type.Equals(VisitorContext.Registry .GetTransformType())) { if (!VisitorContext.EntityIndexMap.TryGetValue(value, out index)) { return; } var transformTypeName = UTinyBuildPipeline.GetJsTypeName(VisitorContext.Registry.GetTransformType() .Dereference(VisitorContext.Registry)); var line = $"e{index}.getComponent({transformTypeName}).appendChild({Entity});"; VisitorContext.Writer.Line(line); } else { if (!VisitorContext.EntityIndexMap.TryGetValue(value, out index)) { return; } VisitorContext.Writer.Line($"{PropertySetter(Property.Name)}(e{index});"); } }
void ICustomVisit <UTinyEnum.Reference> .CustomVisit(UTinyEnum.Reference value) { if (!IsListItem) { return; } var type = value.Type.Dereference(VisitorContext.Registry); var normalized = ExportEnumAsValue ? (type.DefaultValue as UTinyObject)?[value.Name] : $"{UTinyBuildPipeline.GetJsTypeName(type)}.{value.Name}"; VisitorContext.Writer.Line($"{Path}[{ListIndex}] = {normalized};"); }
void ICustomVisit <UTinyObject> .CustomVisit(UTinyObject value) { if (!IsListItem) { return; } var type = value.Type.Dereference(value.Registry); var index = ++VisitorContext.StructIndex; VisitorContext.Writer.Line($"var s{index} = new {UTinyBuildPipeline.GetJsTypeName(type)}();"); value.Properties.Visit(new StructVisitor { VisitorContext = VisitorContext, Path = $"s{index}" }); VisitorContext.Writer.Line($"{Path}[{ListIndex}] = s{index};"); }
public bool DrawLayout() { var module = m_MainModule.Dereference(m_Registry); var system = System.Dereference(m_Registry); if (null == system || system.IsRuntimeIncluded) { return(false); } m_AvailableSystems.Clear(); m_AvailableSystems.AddRange(module.EnumerateDependencies().SystemRefs()); m_AvailableComponentTypes.Clear(); m_AvailableComponentTypes.AddRange(module.EnumerateDependencies().ComponentTypeRefs().Select(r => (UTinyType.Reference)r.Dereference(m_Registry))); EditorGUI.BeginChangeCheck(); using (var scroll = new GUILayout.ScrollViewScope(m_Scroll, GUILayout.ExpandWidth(true))) { m_Scroll = scroll.scrollPosition; EditorGUI.BeginChangeCheck(); system.Name = EditorGUILayout.DelayedTextField("Name", system.Name); if (EditorGUI.EndChangeCheck()) { OnRenameEnded?.Invoke(system); } using (new EditorGUILayout.HorizontalScope()) { EditorGUILayout.PrefixLabel("Description"); system.Documentation.Summary = EditorGUILayout.TextArea(system.Documentation.Summary, GUILayout.Height(50)); } m_ExecuteAfterList.list = new List <UTinySystem.Reference>(system.ExecuteAfter); m_ExecuteAfterList.DoLayoutList(); m_ExecuteBeforeList.list = new List <UTinySystem.Reference>(system.ExecuteBefore); m_ExecuteBeforeList.DoLayoutList(); m_ComponentList.list = new List <UTinyType.Reference>(system.Components); m_ComponentList.DoLayoutList(); system.External = EditorGUILayout.Toggle(new GUIContent("External", "Use this to define systems externally"), system.External); if (system.External) { EditorGUILayout.HelpBox($"This system is assumed to be defined in any included script with the following signature", MessageType.Info); var name = UTinyBuildPipeline.GetJsTypeName(system); EditorGUILayout.SelectableLabel($"{name}.update = function(s,w) {{ /* ... */ }}", "TextArea"); } else { system.IncludeIterator = EditorGUILayout.Toggle("Include Iterator", system.IncludeIterator); EditorGUILayout.Space(); using (new GUIEnabledScope(false)) { var systemPrefix = UTinyBuildPipeline.GenerateSystemPrefix(system); if (system.IncludeIterator) { systemPrefix += UTinyBuildPipeline.GenerateSystemIteratorPrefix(system); } EditorGUILayout.TextArea(systemPrefix); } EditorGUILayout.Space(); system.TextAsset = (TextAsset)EditorGUILayout.ObjectField("Source", system.TextAsset, typeof(TextAsset), false); EditorGUILayout.Space(); if (null != system.TextAsset) { using (new GUIEnabledScope(false)) { var text = system.TextAsset.text; if (text.Length > kMaxChars) { text = text.Substring(0, kMaxChars) + "...\n\n<...etc...>"; } GUILayout.TextArea(text); } } EditorGUILayout.Space(); using (new GUIEnabledScope(false)) { var systemSuffix = UTinyBuildPipeline.GenerateSystemSuffix(system); if (system.IncludeIterator) { systemSuffix = UTinyBuildPipeline.GenerateSystemIteratorSuffix(system) + systemSuffix; } EditorGUILayout.TextArea(systemSuffix); } } } return(EditorGUI.EndChangeCheck()); }
void ICustomVisit <UTinyEnum.Reference> .CustomVisit(UTinyEnum.Reference value) { var type = value.Type.Dereference(VisitorContext.Registry); var normalized = ExportEnumAsValue ? (type.DefaultValue as UTinyObject)?[value.Name] : $"{UTinyBuildPipeline.GetJsTypeName(type)}.{value.Name}"; VisitorContext.Writer.Line($"{PropertySetter(Property.Name)}({normalized});"); }
public static void WriteEntityGroupSetupFunction(UTinyCodeWriter writer, UTinyProject project, UTinyEntityGroup entityGroup, bool writeEntityGroupComponent = true, bool writeEntityLayer = true) { var entityIndex = 0; var entityIndexMap = new Dictionary <UTinyEntity.Reference, int>(); using (writer.Scope("function(w)")) { entityIndexMap.Clear(); foreach (var reference in entityGroup.Entities) { var entity = reference.Dereference(entityGroup.Registry); ++entityIndex; entityIndexMap[reference] = entityIndex; writer.Line($"var e{entityIndex} = w.create({EscapeJsString(entity.Name)});"); } if (writeEntityGroupComponent) { foreach (var reference in entityGroup.Entities) { var index = entityIndexMap[reference]; writer.Line($"e{index}.addComponent(this.Component);"); } } if (writeEntityLayer) { foreach (var reference in entityGroup.Entities) { var index = entityIndexMap[reference]; var entity = reference.Dereference(entityGroup.Registry); writer.Line($"e{index}.addComponent({GetFullyQualifiedLayerName(LayerMask.LayerToName(entity.Layer))});"); } } var context = new VisitorContext { Project = project, Module = project.Module.Dereference(project.Registry), Registry = project.Registry, Writer = writer, EntityIndexMap = entityIndexMap }; entityIndex = 0; foreach (var reference in entityGroup.Entities) { var entity = reference.Dereference(entityGroup.Registry); ++entityIndex; foreach (var component in entity.Components) { var type = component.Type.Dereference(component.Registry); if (null == type) { Debug.LogError($"{UTinyConstants.ApplicationName}: Missing component type, ComponentType=[{component.Type.Name}] Entity=[{entity.Name}] Group=[{entityGroup.Name}]"); continue; } var index = ++context.ComponentIndex; writer.Line($"var c{index} = e{entityIndex}.addComponent({UTinyBuildPipeline.GetJsTypeName(type)});"); component.Properties.Visit(new ComponentVisitor { VisitorContext = context, Path = $"c{index}", Entity = $"e{entityIndex}" }); } } writer.WriteIndent(); writer.WriteRaw("return ["); for (var i = 0; i < entityIndex; i++) { writer.WriteRaw(i != 0 ? $", e{i + 1}" : $"e{i + 1}"); } writer.WriteRaw("];\n"); } writer.Line().Line(); }
/// <summary> /// Generates entry point for the applicaton `main.js` /// This script will contain the system scheduling, window setup and initial group loading /// </summary> private static void GenerateMain(UTinyBuildOptions options, UTinyBuildResults results) { var project = options.Project; var registry = project.Registry; var module = project.Module.Dereference(registry); var file = new FileInfo(Path.Combine(results.BinaryFolder.FullName, KMainFileName)); var writer = new UTinyCodeWriter(); PrependGeneratedHeader(writer, options.Project.Name); var distVersionFile = new FileInfo("UTiny/version.txt"); var versionString = "internal"; if (distVersionFile.Exists) { versionString = File.ReadAllText(distVersionFile.FullName); } writer.LineFormat("console.log('runtime version: {0}');", versionString) .Line(); var namespaces = new Dictionary <string, string>(); foreach (var m in module.EnumerateDependencies()) { if (string.IsNullOrEmpty(m.Namespace)) { continue; } if (m.IsRuntimeIncluded) { writer.Line($"ut.importModule({m.Namespace});"); continue; } string content; namespaces.TryGetValue(m.Namespace, out content); content += m.Documentation.Summary; namespaces[m.Namespace] = content; } UTinyJsdoc.WriteType(writer, "ut.World", "Singleton world instance"); writer.Line("var world;"); using (writer.Scope("ut.main = function()")) { // Create and setup the world writer .Line("world = new ut.World();") .Line("var options = WorldSetup(world);"); // Write configurations var context = new EntityGroupSetupVisitor.VisitorContext { Project = project, Module = project.Module.Dereference(project.Registry), Registry = project.Registry, Writer = writer, EntityIndexMap = null }; var configuration = project.Configuration.Dereference(registry); foreach (var component in configuration.Components) { var moduleContainingType = registry.FindAllByType <UTinyModule>().First(m => m.Types.Contains(component.Type)); if (!module.EnumerateDependencies().Contains(moduleContainingType)) { // Silently ignore components if the module is not included. // This is by design to preserve user data continue; } var type = component.Type.Dereference(component.Registry); var index = ++context.ComponentIndex; writer.Line($"var c{index} = world.config({UTinyBuildPipeline.GetJsTypeName(type)});"); component.Properties.Visit(new EntityGroupSetupVisitor.ComponentVisitor { VisitorContext = context, Path = $"c{index}", }); } // Setup the scheduler writer.Line("var scheduler = world.scheduler();"); // Schedule all systems var systems = project.Module.Dereference(project.Registry).GetSystemExecutionOrder(); foreach (var reference in systems) { var system = reference.Dereference(project.Registry); if (system == null) { Debug.LogWarning($"Can't resolve system named '{reference.Name}' with ID {reference.Id} -- ignoring, you should delete this system"); continue; } var systemModule = UTinyUtility.GetModules(system).FirstOrDefault(); var systemName = UTinyBuildPipeline.GetJsTypeName(systemModule, system); writer.LineFormat("scheduler.schedule({0});", systemName); } // Enable/disable systems foreach (var reference in systems) { var system = reference.Dereference(project.Registry); // By default systems are enabled when scheduled, nothing to write if (system == null || system.Enabled) { continue; } var systemModule = UTinyUtility.GetModules(system).FirstOrDefault(); var systemName = UTinyBuildPipeline.GetJsTypeName(systemModule, system); // @NOTE Disable currently accepts a string and NOT the `ut.System` object writer.LineFormat("scheduler.disable({0});", EscapeJsString(systemName)); } writer.Line("try { ut.Runtime.Service.run(world); } catch (e) { if (e !== 'SimulateInfiniteLoop') throw e; }"); } writer.Line(); using (writer.Scope("function WorldSetup(world)")) { writer.LineFormat("UT_ASSETS_SETUP(world);"); var startupEntityGroup = module.StartupEntityGroup.Dereference(module.Registry); if (null != startupEntityGroup) { writer.Line($"{KEntityGroupNamespace}.{module.Namespace}[\"{module.StartupEntityGroup.Dereference(module.Registry).Name}\"].load(world);"); } else { Debug.LogError($"{UTinyConstants.ApplicationName}: BuildError - No startup group has been set"); } using (writer.Scope("return")) { writer .LineFormat("canvasWidth: {0},", project.Settings.CanvasWidth) .LineFormat("canvasHeight: {0},", project.Settings.CanvasHeight) .LineFormat("canvasAutoResize: {0},", project.Settings.CanvasAutoResize ? "true" : "false"); } #if UNITY_EDITOR_WIN writer.Length -= 2; #else writer.Length -= 1; #endif writer.WriteRaw(";").Line(); } File.WriteAllText(file.FullName, writer.ToString(), Encoding.UTF8); results.BuildReport.GetOrAddChild(UTinyBuildReport.CodeNode).AddChild(file); }
/// <summary> /// Packages system objects to `systems.js` /// /// All systems and system dependencies are written to this file /// </summary> private static void GenerateSystems(UTinyBuildOptions options, UTinyBuildResults results) { var project = options.Project; var report = results.BuildReport.GetOrAddChild(UTinyBuildReport.CodeNode).AddChild(); var file = new FileInfo(Path.Combine(results.BinaryFolder.FullName, KSystemsFileName)); var writer = new UTinyCodeWriter(CodeStyle.JavaScript); PrependGeneratedHeader(writer, options.Project.Name); foreach (var reference in project.Module.Dereference(project.Registry).GetSystemExecutionOrder()) { var system = reference.Dereference(project.Registry); if (system == null) { Debug.LogWarning($"Can't resolve system named '{reference.Name}' with ID {reference.Id} -- ignoring, you should delete this system"); continue; } if (system.External) { continue; } // Fetch the module this system belongs to var systemModule = UTinyUtility.GetModules(system).FirstOrDefault(); if (system.IsRuntimeIncluded) { continue; } var reportSystemPos = writer.Length; UTinyJsdoc.WriteSystem(writer, system); writer.Line($"{UTinyBuildPipeline.GetJsTypeName(systemModule, system)}.update = {UTinyBuildPipeline.GenerateSystemPrefix(system)}"); writer.IncrementIndent(); if (system.IncludeIterator) { writer.Line(UTinyBuildPipeline.GenerateSystemIteratorPrefix(system)); writer.IncrementIndent(); } var text = system.TextAsset ? system.TextAsset.text : string.Empty; if (!string.IsNullOrEmpty(text)) { var lines = text.Split('\n'); foreach (var line in lines) { writer.Line(line); } } if (system.IncludeIterator) { writer.DecrementIndent(); writer.Line("});"); } writer.DecrementIndent(); writer.Line(UTinyBuildPipeline.GenerateSystemSuffix(system)); report.AddChild(AssetDatabase.GetAssetPath(system.TextAsset), Encoding.ASCII.GetBytes(writer.Substring(reportSystemPos)), system.TextAsset); } File.WriteAllText(file.FullName, writer.ToString(), Encoding.UTF8); report.Reset(file); }
public static void WriteSystem(UTinyCodeWriter writer, UTinySystem system) { using (var w = new Writer(writer)) { w.Method(); w.Desc($"System {system.Documentation.Summary}"); if (system.Components.Count > 0) { var sb = new StringBuilder(); sb.Append("Components ["); for (var i = 0; i < system.Components.Count; i++) { var componentRef = system.Components[i]; var component = componentRef.Dereference(system.Registry); if (null != component) { sb.AppendFormat(i == 0 ? "{{@link {0}}}" : ", {{@link {0}}}", UTinyBuildPipeline.GetJsTypeName(component)); } else { throw new Exception($"System component is missing System=[{system.Name}] Component=[{componentRef.Name}]"); } } sb.Append("]"); w.Line(sb.ToString()); } if (system.ExecuteAfter.Count > 0) { var sb = new StringBuilder(); sb.Append("Execute After ["); for (var i = 0; i < system.ExecuteAfter.Count; i++) { var executeAfterRef = system.ExecuteAfter[i]; var executeAfter = executeAfterRef.Dereference(system.Registry); if (null != executeAfter) { sb.AppendFormat(i == 0 ? "{{@link {0}}}" : ", {{@link {0}}}", UTinyBuildPipeline.GetJsTypeName(executeAfter)); } else { throw new Exception($"System reference is missing System=[{system.Name}] ExecuteAfter=[{executeAfterRef.Name}]"); } } sb.Append("]"); w.Line(sb.ToString()); } if (system.ExecuteBefore.Count > 0) { var sb = new StringBuilder(); sb.Append("Execute Before ["); for (var i = 0; i < system.ExecuteBefore.Count; i++) { var executeBeforeRef = system.ExecuteBefore[i]; var executeBefore = executeBeforeRef.Dereference(system.Registry); if (null != executeBefore) { sb.AppendFormat(i == 0 ? "{{@link {0}}}" : ", {{@link {0}}}", UTinyBuildPipeline.GetJsTypeName(executeBefore)); } else { throw new Exception($"System reference is missing System=[{system.Name}] ExecuteBefore=[{executeBeforeRef.Name}]"); } } sb.Append("]"); w.Line(sb.ToString()); } w.Param("ut.Scheduler", "sched"); w.Param("ut.World", "world"); } }