Example #1
0
            private static void ExportWebP(string path, string name, Texture2D texture, int quality, ICollection <FileInfo> output)
            {
                var hasAlpha      = ReallyHasAlpha(texture);
                var outputTexture = CopyTexture(texture, hasAlpha ? TextureFormat.RGBA32 : TextureFormat.RGB24);

                var tempPngInputPath = Path.Combine(Application.temporaryCachePath, "webp-input.png");

                File.WriteAllBytes(tempPngInputPath, outputTexture.EncodeToPNG());

                quality = Math.Max(0, Math.Min(100, quality));

                var dstFile = new FileInfo(Path.Combine(path, name + ".webp"))
                              .FullName;

                UTinyBuildUtilities.RunInShell(
                    $"cwebp -quiet -q {quality} \"{tempPngInputPath}\" -o \"{dstFile}\"",
                    new ShellProcessArgs()
                {
                    ExtraPaths = ImageUtilsPath().AsEnumerable()
                });

                File.Delete(tempPngInputPath);

                output.Add(new FileInfo(dstFile));
            }
Example #2
0
 private void CleanUp()
 {
     // We will keep the bug-report zip file, but clean up everything-else.
     if (Directory.Exists(BugProjectPath))
     {
         UTinyBuildUtilities.PurgeDirectory(new DirectoryInfo(BugProjectPath));
     }
 }
        private static void InstallRuntime(bool force, bool silent)
        {
            try
            {
                var installLocation = new DirectoryInfo("UTiny");
                var versionFile     = new FileInfo(Path.Combine(installLocation.FullName, "lastUpdate.txt"));
                var sourcePackage   = new FileInfo(UTinyConstants.PackagePath + "tiny-runtime-dist.zip");
                var shouldUpdate    = sourcePackage.Exists && (!versionFile.Exists || versionFile.LastWriteTimeUtc < sourcePackage.LastWriteTimeUtc);

                if (!force && !shouldUpdate)
                {
                    if (!silent)
                    {
                        Debug.Log("Tiny: Runtime is already up to date");
                    }
                    return;
                }

                if (!sourcePackage.Exists)
                {
                    if (!silent)
                    {
                        Debug.LogError($"Tiny: could not find {sourcePackage.FullName}");
                    }
                    return;
                }

                if (installLocation.Exists)
                {
                    EditorUtility.DisplayProgressBar($"{UTinyConstants.ApplicationName} Runtime", "Removing old runtime...", 0.0f);
                    UTinyBuildUtilities.PurgeDirectory(installLocation);
                }
                EditorUtility.DisplayProgressBar($"{UTinyConstants.ApplicationName} Runtime", "Installing new runtime...", 0.5f);
                UTinyBuildUtilities.UnzipFile(sourcePackage.FullName, installLocation.Parent);
                File.WriteAllText(versionFile.FullName, $"{sourcePackage.FullName} install time: {DateTime.UtcNow.ToString()}");

#if UNITY_EDITOR_OSX
                // TODO: figure out why UnzipFile does not preserve executable bits in some cases
                // chmod +x any native executables here
                UTinyBuildUtilities.RunInShell("chmod +x cwebp moz-cjpeg pngcrush",
                                               new ShellProcessArgs()
                {
                    WorkingDirectory = new DirectoryInfo(GetToolDirectory("images/osx")),
                    ExtraPaths       = "/bin".AsEnumerable(), // adding this folder just in case, but should be already in $PATH
                    ThrowOnError     = false
                });
#endif

                Debug.Log($"Installed {UTinyConstants.ApplicationName} runtime at: {installLocation.FullName}");
            }
            finally
            {
                EditorUtility.ClearProgressBar();
            }
        }
        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);
        }
Example #5
0
        private bool PackagingDependencies()
        {
            IEnumerable <string> packagableFiles    = k_EmptyPackageableFiles;
            IEnumerable <string> nonPackagableFiles = k_EmptyNonPackageableFiles;

            foreach (var group in m_Paths.GroupBy(p => p.StartsWith(DataPath)))
            {
                var inAssetFolder = group.Key;
                if (inAssetFolder)
                {
                    packagableFiles = group.Select(RelativeToProjectFolder);
                }
                else
                {
                    nonPackagableFiles = group;
                }
            }

            if (nonPackagableFiles.Any())
            {
                string zipFilename = $"{DataPath}/external-files.zip";
                UTinyBuildUtilities.ZipPaths(nonPackagableFiles.ToArray(), zipFilename);
                var relativeZipPath = RelativeToProjectFolder(zipFilename);
                AssetDatabase.ImportAsset(relativeZipPath, ImportAssetOptions.ForceSynchronousImport);
                File.Move(zipFilename, $"{BugProjectPath}/{relativeZipPath}");
                File.Move($"{zipFilename}.meta", $"{BugProjectPath}/{relativeZipPath}.meta");
            }

            if (packagableFiles.Any())
            {
                var toPackage         = packagableFiles.ToArray();
                var targetPackagePath = $"{BugProjectPath}/{k_BugPackagePath}";
                AssetDatabase.ExportPackage(toPackage, targetPackagePath, ExportPackageOptions.IncludeDependencies | ExportPackageOptions.Recurse);
            }

            return(true);
        }
Example #6
0
        private void Send(MouseUpEvent evt)
        {
            if (Directory.Exists(BugReportPath))
            {
                UTinyBuildUtilities.PurgeDirectory(new DirectoryInfo(BugReportPath));
            }
            EditorUtility.DisplayProgressBar($"{UTinyConstants.ApplicationName} Bug Report", "Validating Fields", 0.0f);

            m_PathsOnSend.AddRange(m_Paths);
            try
            {
                if (!RunUntilFailure(m_SendMethods, true))
                {
                    EditorUtility.ClearProgressBar();
                    // Failed to send the bug report to Jira, but successfully created the zip file.
                    if (File.Exists(ZipFilePath))
                    {
                        Debug.Log($"{UTinyConstants.ApplicationName}: Could not send the bug report. you can send it manually by emailing the '{RelativeToProjectFolder(ZipFilePath)}' file to '*****@*****.**'" +
                                  "\nNo need to provide additional description, it is all packed in the zip file itself.");
                        EditorUtility.RevealInFinder(ZipFilePath);
                        Close();
                    }
                }
                else
                {
                    Debug.Log($"{UTinyConstants.ApplicationName}: bug sent successfully - thanks!");
                    Close();
                }
            }
            finally
            {
                CleanUp();
                m_PathsOnSend.Clear();
                EditorUtility.ClearProgressBar();
            }
        }
Example #7
0
            private static void ExportJpgOptimized(string path, string name, Texture2D texture, int quality, ICollection <FileInfo> output)
            {
                var colorFilePath = $"{Path.Combine(path, name)}.jpg";

                var outputTexture = CopyTexture(texture, TextureFormat.RGB24);
                //var tempPngInputPath = Path.Combine(Application.temporaryCachePath, "webp-input.png");
                var tempPngInputPath = $"{Path.Combine(path, name)}-input.png";

                File.WriteAllBytes(tempPngInputPath, outputTexture.EncodeToPNG());

                quality = Math.Max(0, Math.Min(100, quality));

                // this will build progressive jpegs by default; -baseline stops this.
                // progressive results in better compression
                UTinyBuildUtilities.RunInShell(
                    $"moz-cjpeg -quality {quality} -outfile \"{colorFilePath}\" \"{tempPngInputPath}\"",
                    new ShellProcessArgs()
                {
                    ExtraPaths = ImageUtilsPath().AsEnumerable()
                });

                File.Delete(tempPngInputPath);

                output.Add(new FileInfo(colorFilePath));

                if (ReallyHasAlpha(texture))
                {
                    // @TODO Optimization by reusing the texture above
                    var outputAlphaTexture = CopyTexture(texture, TextureFormat.RGBA32);

                    var pixels = outputAlphaTexture.GetPixels32();

                    // broadcast alpha to color
                    for (var i = 0; i < pixels.Length; i++)
                    {
                        pixels[i].r = pixels[i].a;
                        pixels[i].g = pixels[i].a;
                        pixels[i].b = pixels[i].a;
                        pixels[i].a = 255;
                    }

                    outputAlphaTexture.SetPixels32(pixels);
                    outputAlphaTexture.Apply();

                    //var pngCrushInputPath = Path.Combine(Application.temporaryCachePath, "alpha-input.png");
                    var pngCrushInputPath = $"{Path.Combine(path, name)}_a-input.png";
                    var alphaFilePath     = $"{Path.Combine(path, name)}_a.png";

                    using (var stream = new FileStream(pngCrushInputPath, FileMode.Create))
                    {
                        var bytes = outputAlphaTexture.EncodeToPNG();
                        stream.Write(bytes, 0, bytes.Length);
                    }

                    // convert to 8-bit grayscale png
                    UTinyBuildUtilities.RunInShell(
                        $"pngcrush -s -c 0 \"{pngCrushInputPath}\" \"{alphaFilePath}\"",
                        new ShellProcessArgs()
                    {
                        ExtraPaths = ImageUtilsPath().AsEnumerable()
                    });

                    output.Add(new FileInfo(alphaFilePath));
                }
            }
        /// <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);
        }
Example #9
0
 private bool ZippingBugReport()
 {
     return(UTinyBuildUtilities.ZipFolder(new DirectoryInfo(BugProjectPath), ZipFilePath));
 }
        public static UTinyBuildResults Build(UTinyBuildOptions options)
        {
            if (options?.Project == null || options.Destination == null)
            {
                throw new ArgumentException($"{UTinyConstants.ApplicationName}: invalid build options provided", nameof(options));
            }

            var buildStart = DateTime.Now;

            var           results = new UTinyBuildResults();
            IUTinyBuilder builder = null;

            switch (options.Platform)
            {
            case UTinyPlatform.HTML5:
                builder = new UTinyHTML5Builder();
                break;

            default:
                throw new ArgumentException($"{UTinyConstants.ApplicationName}: build platform not supported", nameof(options));
            }

            try
            {
                EditorUtility.DisplayProgressBar(ProgressBarTitle, "Build started for " + options.Platform.ToString(),
                                                 0.0f);

                var destFolder = options.Destination;
                destFolder.Create();

                // BUILD = <DEST>/PLATFORM/CONFIG
                var buildFolder = new DirectoryInfo(GetBuildDirectory(options.Project, options.Platform, options.Configuration));

                results.OutputFolder = buildFolder;

                UTinyBuildUtilities.PurgeDirectory(buildFolder);
                buildFolder.Create();

                options.Destination = results.BinaryFolder = buildFolder;

                var idlFile = new FileInfo(Path.Combine(buildFolder.FullName, "generated.cs"));
                UTinyIDLGenerator.GenerateIDL(options.Project, idlFile);

                var distFolder = GetRuntimeDistFolder();

                var bindGem = new FileInfo(Path.Combine(
                                               distFolder.FullName, "bindgem/BindGem/bin/Release/BindGem.exe"));

                var exeName = "\"" + bindGem.FullName + "\"";

                // always call bindgem with mono for consistency
                exeName = "mono " + exeName;

                // reference the core runtime file
                var bindReferences = $"-r \"{RuntimeDefsAssemblyPath}\"";

                UTinyBuildUtilities.RunInShell(
                    $"{exeName} -j {bindReferences} -o bind-generated {idlFile.Name}",
                    new ShellProcessArgs()
                {
                    WorkingDirectory = buildFolder,
                    ExtraPaths       = TinyPreferences.MonoDirectory.AsEnumerable()
                });

                // @TODO Perform a full refresh before building

                builder.Build(options, results);

                results.BuildReport.Update();

                Debug.Log($"{UTinyConstants.ApplicationName} project generated at: {results.BinaryFolder.FullName}");

                TinyEditorAnalytics.SendBuildEvent(options.Project, results, DateTime.Now - buildStart);
                return(results);
            }
            catch (Exception ex)
            {
                TinyEditorAnalytics.SendException("BuildPipeline.Build", ex);
                throw;
            }
            finally
            {
                EditorUtility.ClearProgressBar();
                UTinyEditorUtility.RepaintAllWindows();
            }
        }