Skip to content

Instantly share code, notes, and snippets.

@msilvestro
Last active May 18, 2023 22:09
Show Gist options
  • Save msilvestro/0cb78bf4aeb0fd8d0697db0f38b0c4ae to your computer and use it in GitHub Desktop.
Save msilvestro/0cb78bf4aeb0fd8d0697db0f38b0c4ae to your computer and use it in GitHub Desktop.
Run a Unity build while continuing to work on your project.

Unity Parallel Build

If you are a Unity developer and you don't have access to Unity Cloud Build or a dedicated computer, you might find the build process of Unity a bit tedious. You have to stop working for several minutes, especially when building for WebGL.

Well, no more! With this script you can start the build process and, while waiting, continuing to do all sort of works on your Unity project and not waste time.

How to install

  • Copy ParallelBuild.ps1 and buildsettings.json wherever you want, even though I suggest placing them at the root of your project. This way, you can omit the projectPath and build from the terminal of your preferred code editor while working on the project.
  • Copy WebGLBuilder.cs in a folder called Editor inside of you Assets folder, for instance: Assets/Editor/WebGLBuilder.cs. What is important is that the file has a parent folder called Editor inside of Assets.
  • Tweak the buildsettings.json file according to your needs:
    • projectPath: the path of you project (default to the directory the ParallelBuild.ps1 file is placed in).
    • buildPath: the path relative to the root of the project where the build will be placed.
    • parallel: whether the build should be parallel or a standard one (but why would you?)
    • publishToItch: whether to publish the game on Itch when the build is finished successfully.
    • itchUser: the Itch user you want to publish to
    • itchGame: the name of the Itch game you want to publish to
  • Make sure you can execute the ParallelBuild.ps1 file, if you don't you can allow its execution with:
Unblock-File -Path \ParallelBuild.ps1

How to run

  • Simply type
./ParallelBuild.ps1

How it works

This script simply makes a copy of the project and then runs the build on the copy, allowing you to continue working on the original one. At the end, the copied project is deleted. Be careful, when this script is working you can find the copied project listed in the Unity Hub, so don't mistake it for the original project.

Limitations

This script is quite simple and for the moment has some limitations, which I may address in the future, such as:

  • Works only for WebGL builds
  • Works only on Windows
  • Show the copied project in the Unity Hub while the script is working
  • It is cumbersome to install and update
{
"projectPath": "C:\\Users\\user\\source\\unity\\Incredible Game",
"buildPath": "Builds/WebGL",
"itchUser": "user",
"itchGame": "game",
"parallel": true,
"publishToItch": true
}
function Copy-UnityProject {
param (
[string] $ProjectPath = "."
)
$ProjectPath = Resolve-Path -Path $ProjectPath
$projectFolder = $ProjectPath | Split-Path -Leaf
$tempProjectPath = Join-Path -Path $env:TEMP -ChildPath $projectFolder
& robocopy $ProjectPath $tempProjectPath /mir `
/xd (Join-Path -Path $ProjectPath -ChildPath Build) `
/xd (Join-Path -Path $ProjectPath -ChildPath Library) `
/xd (Join-Path -Path $ProjectPath -ChildPath Logs) `
/xd (Join-Path -Path $ProjectPath -ChildPath Temp) `
/nfl /ndl | Write-Host
return $tempProjectPath
}
function Build-UnityWebGL {
param (
[string] $ProjectPath = ".",
[string] $BuildPath = ""
)
$ProjectPath = Resolve-Path -Path $ProjectPath
if ($BuildPath -eq "") {
$BuildPath = Join-Path -Path $ProjectPath -ChildPath "Build/WebGL"
}
$projectVersion = Get-Content (Join-Path -Path $ProjectPath -ChildPath ProjectSettings/ProjectVersion.txt)
| Select-String -Pattern "^m_EditorVersion: (.*)$"
| % { $_.Matches.Groups[1].Value }
if (Test-Path -Path $BuildPath){
Remove-Item -Path $BuildPath -Recurse | Out-Null
}
New-Item -Path $BuildPath -ItemType "directory" | Out-Null
$BuildPath = Resolve-Path -Path $BuildPath
Write-Output "Building Unity WebGL..."
& "C:\Program Files\Unity\Hub\Editor\$projectVersion\Editor\Unity.exe" -quit -batchmode -projectpath $ProjectPath -logFile - `
-executeMethod ParallelBuild.WebGLBuilder.Build -buildpath $BuildPath
| Write-Output
if ($LastExitCode -ne 0) {
throw "Error during the build, error code $LastExitCode"
}
}
function Publish-Itch {
param (
[Parameter(Mandatory=$true)] [string] $BuildPath,
[Parameter(Mandatory=$true)] [string] $ItchUser,
[Parameter(Mandatory=$true)] [string] $ItchGame
)
$BuildPath = Resolve-Path -Path $BuildPath
Write-Output "Publishing to Itch..."
& "butler" push $BuildPath $ItchUser/${ItchGame}:webgl
& "butler" status $ItchUser/${ItchGame}:webgl
}
function Remove-RecentlyUsedProjectPath {
param (
[Parameter(Mandatory=$true)] [string] $ProjectPath
)
$foundKey = $false
$key = 'HKCU:\Software\Unity Technologies\Unity Editor 5.x'
Get-Item -Path $key | Select-Object -ExpandProperty Property | Where-Object {$_.StartsWith("RecentlyUsedProjectPaths")} | % {
$value = (Get-ItemProperty -Path $key -Name $_).$_
$stringValue = [System.Text.Encoding]::Default.GetString($value)
$adjustedPath = $stringValue -replace '/', '\'
if ($adjustedPath -eq $ProjectPath) {
Write-Output "Removing recently used project path '$adjustedPath'..."
Remove-ItemProperty -Path $key -Name $_
$foundKey = $true
}
}
if ($foundKey -eq $false) {
Write-Warning "No recently used project found."
}
}
$ErrorActionPreference = "Stop"
$buildSettingsPath = Join-Path -Path $PSScriptRoot -ChildPath buildsettings.json
$settings = Get-Content -Path $buildSettingsPath | ConvertFrom-Json
$projectPath = $settings.projectPath
if ($projectPath -eq $null) {
$projectPath = $PSScriptRoot
}
if ($settings.parallel -eq $true) {
Write-Output "Copying project to temporary folder (do not edit files)..."
$projectPath = Copy-UnityProject -ProjectPath $projectPath
Write-Output "Done. You can continue working on your Unity project."
}
if ([System.IO.Path]::IsPathRooted($settings.buildPath)) {
$buildPath = $settings.buildPath;
} else {
$buildPath = Join-Path -Path $projectPath -ChildPath $settings.buildPath
}
Build-UnityWebGL -ProjectPath $projectPath -BuildPath $buildPath
if ($settings.parallel -eq $true) {
Remove-RecentlyUsedProjectPath -ProjectPath $projectPath
}
if ($settings.publishToItch -eq $true) {
Publish-Itch -BuildPath $buildPath -ItchUser $settings.itchUser -ItchGame $settings.itchGame
}
[System.Console]::Beep()
using System;
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace ParallelBuild
{
public class WebGLBuilder
{
private static string[] GetAllScenes()
{
return EditorBuildSettings.scenes
.Where(scene => scene.enabled)
.Select(scene => scene.path)
.ToArray();
}
private static string GetArg(string name, string defaultValue = null)
{
var args = Environment.GetCommandLineArgs();
for (int i = 0; i < args.Length; i++)
{
if (args[i] == name && args.Length > i + 1)
{
return args[i + 1];
}
}
return defaultValue;
}
public static bool Build()
{
return Build(GetArg("-buildpath", "Build/WebGL"));
}
public static bool Build(string buildPath)
{
BuildPlayerOptions options = new BuildPlayerOptions()
{
locationPathName = buildPath,
target = BuildTarget.WebGL,
scenes = GetAllScenes()
};
var buildReport = BuildPipeline.BuildPlayer(options);
return buildReport.summary.result == UnityEditor.Build.Reporting.BuildResult.Succeeded;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment