Пример #1
0
            private static string ImageUtilsPath()
            {
                var path = UTinyBuildPipeline.GetToolDirectory("images");

#if UNITY_EDITOR_WIN
                path = Path.Combine(path, "win");
#else
                path = Path.Combine(path, "osx");
#endif
                return(new DirectoryInfo(path).FullName);
            }
        /// <summary>
        /// Generates `wsclient.js` to handle live-linking
        /// </summary>
        private static void GenerateWebSocketClient(UTinyBuildOptions options, UTinyBuildResults results)
        {
            if (!options.Project.Settings.IncludeWSClient)
            {
                return;
            }

            // Put local http server address into the wsclient script
            var content = File.ReadAllText(Path.Combine(UTinyBuildPipeline.GetToolDirectory("wsclient"), KWebSocketClientFileName));

            content = content.Replace("{{IPADDRESS}}", UTinyServer.Instance.LocalIPAddress);

            // Write wsclient to binary dir
            var file = new FileInfo(Path.Combine(results.BinaryFolder.FullName, KWebSocketClientFileName));

            File.WriteAllText(file.FullName, content, Encoding.UTF8);

            results.BuildReport.GetOrAddChild(UTinyBuildReport.CodeNode).AddChild(file);
        }
        private bool HostContent(string contentDir)
        {
            StopHostingContent();

            // Setup a signal event with handlers
            string                   stdout = "", stderr = "";
            ManualResetEvent         isRunning      = new ManualResetEvent(false);
            DataReceivedEventHandler outputReceived = (sender, e) => { stdout += e.Data; isRunning.Set(); };
            DataReceivedEventHandler errorReceived  = (sender, e) => { stderr += e.Data; isRunning.Set(); };

            // Start new local http server
            var ppid            = Process.GetCurrentProcess().Id;
            var port            = UTinyEditorApplication.Project.Settings.LocalHTTPServerPort;
            var httpServerDir   = new DirectoryInfo(UTinyBuildPipeline.GetToolDirectory("httpserver"));
            var unityVersion    = InternalEditorUtility.GetUnityVersion();
            var profilerVersion = unityVersion.Major > 2018 || (unityVersion.Major == 2018 && unityVersion.Minor > 1) ? 0x20180123 : 0x20170327;

            m_LocalServerProcess = UTinyBuildUtilities.RunNodeNoWait(httpServerDir, "index.js", $"--pid {ppid} --port {port} --dir \"{contentDir}\" --profiler " + profilerVersion, outputReceived, errorReceived);
            if (m_LocalServerProcess == null)
            {
                throw new Exception("Failed to create local http server process.");
            }

            // Wait for the process to write something in either stdout or stderr
            isRunning.WaitOne(3000);

            // Check if process state is valid
            if (m_LocalServerProcess.HasExited || stderr.Length > 0)
            {
                var errorMsg = "Failed to start local http server.";
                if (stderr.Length > 0)
                {
                    errorMsg += $"\n{stderr}";
                }
                else if (stdout.Length > 0)
                {
                    errorMsg += $"\n{stdout}";
                }
                UnityEngine.Debug.LogError(errorMsg);
                return(false);
            }
            return(true);
        }
        /// <summary>
        /// Generates `libwebp.js` to handle WebP decompressor
        /// </summary>
        private static void GenerateWebPDecompressor(UTinyBuildOptions options, UTinyBuildResults results)
        {
            // Check if project use WebP texture format
            var module   = options.Project.Module.Dereference(options.Project.Registry);
            var webpUsed = AssetIterator.EnumerateAssets(module)
                           .Select(a => a.Object)
                           .OfType <Texture2D>()
                           .Select(t => UTinyUtility.GetAssetExportSettings(options.Project, t))
                           .OfType <UTinyTextureSettings>()
                           .Any(s => s.FormatType == TextureFormatType.WebP);

            // Warn about WebP usages
            if (options.Project.Settings.IncludeWebPDecompressor)
            {
                if (!webpUsed)
                {
                    Debug.LogWarning("This project does not uses the WebP texture format, but includes the WebP decompressor code. To reduce build size, it is recommended to disable \"Include WebP Decompressor\" in project settings.");
                }
            }
            else // WebP decompressor not included, do not copy to binary dir
            {
                if (webpUsed)
                {
                    Debug.LogWarning("This project uses the WebP texture format, but does not include the WebP decompressor code. The content will not load in browsers that do not natively support the WebP format. To ensure maximum compatibility, enable \"Include WebP Decompressor\" in project settings.");
                }
                return;
            }

            // Copy libwebp to binary dir
            var srcFile = Path.Combine(UTinyBuildPipeline.GetToolDirectory("libwebp"), KWebPDecompressorFileName);
            var dstFile = Path.Combine(results.BinaryFolder.FullName, KWebPDecompressorFileName);

            File.Copy(srcFile, dstFile);

            results.BuildReport.GetOrAddChild(UTinyBuildReport.CodeNode).AddChild(new FileInfo(dstFile));
        }
        /// <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);
        }