コード例 #1
0
        /// <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);
        }
コード例 #2
0
        /// <summary>
        /// Outputs the final `index.html` file
        /// </summary>
        private static void GenerateHTML(UTinyBuildOptions options, UTinyBuildResults results)
        {
            var project = options.Project;

            var settingsFile         = new FileInfo(Path.Combine(results.BinaryFolder.FullName, KSettingsFileName));
            var runtimeFile          = new FileInfo(Path.Combine(results.BinaryFolder.FullName, KRuntimeFileName));
            var bindingsFile         = new FileInfo(Path.Combine(results.BinaryFolder.FullName, KBindingsFileName));
            var assetsFile           = new FileInfo(Path.Combine(results.BinaryFolder.FullName, KAssetsFileName));
            var entityGroupsFile     = new FileInfo(Path.Combine(results.BinaryFolder.FullName, KEntityGroupsFileName));
            var systemsFile          = new FileInfo(Path.Combine(results.BinaryFolder.FullName, KSystemsFileName));
            var codeFile             = new FileInfo(Path.Combine(results.BinaryFolder.FullName, KCodeFileName));
            var mainFile             = new FileInfo(Path.Combine(results.BinaryFolder.FullName, KMainFileName));
            var webSocketClientFile  = new FileInfo(Path.Combine(results.BinaryFolder.FullName, KWebSocketClientFileName));
            var webpDecompressorFile = new FileInfo(Path.Combine(results.BinaryFolder.FullName, KWebPDecompressorFileName));

            // nb: this writer is not HTML-friendly
            var writer = new UTinyCodeWriter()
            {
                CodeStyle = new CodeStyle()
                {
                    BeginBrace  = string.Empty,
                    EndBrace    = string.Empty,
                    BraceLayout = BraceLayout.EndOfLine,
                    Indent      = "  ",
                    NewLine     = Environment.NewLine
                }
            };

            writer.Line("<!DOCTYPE html>");
            using (writer.Scope("<html>"))
            {
                using (writer.Scope("<head>"))
                {
                    writer.Line("<meta charset=\"UTF-8\">");
                    if (UsesAdSupport(project))
                    {
                        writer.Line("<script src=\"mraid.js\"></script>");
                    }

                    if (project.Settings.RunBabel)
                    {
                        // Babelize user code
                        var          title         = $"{UTinyConstants.ApplicationName} Build";
                        const string messageFormat = "Transpiling {0} to ECMAScript 5";

                        EditorUtility.DisplayProgressBar(title, "Transpiling to ECMAScript 5", 0.0f);
                        try
                        {
                            // We only need to transpile user authored code
                            var userCode = new [] { systemsFile, codeFile };
                            var babelDir = new DirectoryInfo(UTinyBuildPipeline.GetToolDirectory("babel"));
                            for (var i = 0; i < userCode.Length; i++)
                            {
                                var file = userCode[i];
                                EditorUtility.DisplayProgressBar(title, string.Format(messageFormat, file.Name), i / (float)userCode.Length);
                                UTinyBuildUtilities.RunNode(babelDir, "index.js", $"\"{file.FullName}\" \"{file.FullName}\"");
                            }
                        }
                        finally
                        {
                            EditorUtility.ClearProgressBar();
                        }
                    }

                    // Gather all game files (order is important)
                    var files = new List <FileInfo>
                    {
                        settingsFile,
                        runtimeFile,
                        bindingsFile,
                        assetsFile,
                        entityGroupsFile,
                        systemsFile,
                        codeFile,
                        mainFile,
                        webSocketClientFile,
                        webpDecompressorFile
                    }.Where(file => file != null && file.Exists).ToList();

                    // Extra steps for Release config
                    if (options.Configuration == UTinyBuildConfiguration.Release)
                    {
                        // Minify JavaScript
                        var gameFile = new FileInfo(Path.Combine(results.BinaryFolder.FullName, "game.js"));
                        EditorUtility.DisplayProgressBar($"{UTinyConstants.ApplicationName} Build", "Minifying JavaScript code...", 0.0f);
                        try
                        {
                            var minifyDir = new DirectoryInfo(UTinyBuildPipeline.GetToolDirectory("minify"));
                            UTinyBuildUtilities.RunNode(minifyDir, "index.js", $"\"{gameFile.FullName}\" {String.Join(" ", files.Select(file => '"' + file.FullName + '"'))}");
                            files.ForEach(file => file.Delete());
                        }
                        finally
                        {
                            EditorUtility.ClearProgressBar();
                        }

                        // Package as single html file
                        if (project.Settings.SingleFileHtml)
                        {
                            writer.Line("<script type=\"text/javascript\">");
                            writer.WriteRaw(File.ReadAllText(gameFile.FullName));
                            writer.Line();
                            writer.Line("</script>");
                            gameFile.Delete();
                        }
                        else
                        {
                            writer.LineFormat("<script src=\"{0}\"></script>", gameFile.Name);
                        }
                    }
                    else
                    {
                        files.ForEach(file => writer.LineFormat("<script src=\"{0}\"></script>", file.Name));
                    }
                    writer.LineFormat("<title>{0}</title>", project.Name);
                    writer.CodeStyle.EndBrace = "</head>";
                }
                using (writer.Scope("<body>"))
                {
                    writer.CodeStyle.EndBrace = "</body>";
                }
                writer.CodeStyle.EndBrace = "</html>";
            }

            // Write final index.html file
            var htmlFile = new FileInfo(Path.Combine(results.BinaryFolder.FullName, KHtmlFileName));

            File.WriteAllText(htmlFile.FullName, writer.ToString(), Encoding.UTF8);
        }
コード例 #3
0
 public void Line(string content)
 {
     m_Writer.LineFormat(" * {0}", content);
 }