/// <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); }