If you’ve looked at my recent Unity-related posts and downloaded the projects, you might have noticed I have .bat files like CreateAndUploadWebGLBuild.bat in there to cleanly create final versions easily.
Great. But if you run this .bat file while you are working on the game with the Unity editor, you’ll get this error:
Aborting batchmode due to failure: Fatal Error! It looks like another Unity instance is running with this project open. Multiple Unity instances cannot open the same project.
Ugh. WebGL builds are especially are incredible slow, so this is a big productivity waster if you’re doing a lot of WebGL testing. (If you work at a big company and waiting for builds is your favorite time to make coffee and catch up on reddit, well, close this page right now and hope your boss never reads this!)
Maybe you could use Unity’s Cloud Build but there are some down sides:
- Cost $9 a month?
- Requires that you commit each change to a cvs such as svn, perforce, or git
- I doubt it can do custom post build commands such as code signing, building a final installer, or rscying files to a linux server and restarting the process. I guess you could do those things yourself when the build is done, but heck, why not just handle the build yourself from the start.
- Requires that all your assets are also on cvs (?)
The DIY way
So let’s do it old school with … yep, you guessed it… even more .bat files! The secret is very simple, Unity will allow you to build in the background if the project directory is different.
You just need to copy your entire project to a temporary folder, then run Unity.exe with parms to do a headless build like normal.
So when you are in a good place with your project and would like to start a background build, hit Ctrl-S to save, then run your “CopyToTempDirAndBuild.bat” file.
After a couple seconds the initial copy is done and it’s safe to continue working while the build is happening in the temp directory – any changes will not be in the temp directory, so your build in progress won’t be affected. So you can keep working away, without ever closing your main unity editor window.
It’s not especially tricky to do, but here are some .bat files to look at as an example that could be tweaked.
To copy a directory tree to a temp dir: (it assumes the .bat is run from the directory that’s going to be copied)
:this sets some info about the project, for example, it causes %APP_NAME% to hold our main directory name call app_info_setup.bat rmdir ..\%APP_NAME%Temp%1 /S /Q echo Cloning %APP_NAME% to temp dir %APP_NAME%Temp%1... mkdir ..\%APP_NAME%Temp%1 xcopy . ..\%APP_NAME%Temp%1\ /E /F /Y /EXCLUDE:%cd%\CloneExclusionList.txt
Note: You may wonder why I’m being repetitive and using “Temp” everywhere instead of including it in a variable. It’s because you NEVER, NEVER use things like rmdir with a variable if you can help it, because at some point, that variable is going to be set incorrectly. It might be .. or / or something and you’ll delete your whole hard drive. Safety first.
Another note: %cd% is a DOS trick to get the current full directory
CloneExclusionList.txt contains dirs we don’t want to waste time copying:
Temp\ Library\ build\win build\linux build\web\Build
:this sets some info about the project, for example, it causes %APP_NAME% to hold our main directory name call app_info_setup.bat :Setting no pause causes our .bat files to not do pause commands when they are done set NO_PAUSE=1 :First, let's customize the directory name we're going to close to, by adding a postfix to make it unique SET CLONE_DIR_POSTFIX=WebGL :Now let's actually make it, we'll pass in the postfix as a parm call CloneToTempDir.bat %CLONE_DIR_POSTFIX% :Move to build dir cd ../%APP_NAME%Temp%CLONE_DIR_POSTFIX% :Do the actual build call BuildWebGL.bat call UploadWebGLRsync.bat :Move back out of it cd .. :Delete the temp dir we were just using rmdir %APP_NAME%Temp%CLONE_DIR_POSTFIX% /S /Q pause
This calls CloneToTempDir.bat with the parm “WebGL” which gets appended to the <AppName>Temp dir.
It then “calls” (this means run another .bat, and come back when it’s done) .bats to create the webgl build and also upload it to the website.
It then destroys the temp directory completely, a good idea because Unity will mark it as the last project and you don’t want to accidently work on that directory later.
If you’ve got 16 threads sitting around like I do, it might make sense to build MORE THAN ONE version at a time. (now you see why I use a custom temp dir name for each build)
Apparently, Unity doesn’t care how many simultaneous builds you’re doing on a single computer, as long as its license is valid. (I’m using a pro license)
The key to running parallel builds is to use the “start” command instead of “call”. This means “run this, but instead of waiting, just continue running the rest of this .bat file”.
start BuildAndUploadWebGLInClonedDir.bat start BuildAndUploadLinux64InClonedDir.bat
So, including the Unity editor you have open, when this is run you’ll have THREE instances of Unity running on the same computer at once. It all works fine!
Continuous integration as a background operation on the same computer you develop on
If you add a “goto :start” at the bottom of your .bat and a “:start” label at the top, you can “clone and build” non-stop all day. I don’t see this as very useful as it’s going to break all the time as we’re not doing controlled commits with a cvs but I thought I’d throw that there.