Porting Your Game To WebGL – Chapter 2


In the
previous chapter, we covered various considerations and preparations for porting the game to WebGL.

Producing A Successful Build With IL2CPP and Emscripten

It’s true that building Angry Bots, a Unity example project, is fairly easy. But such projects usually don’t compare to large scale games.

To produce the build, Unity will send the .Net code through a pipeline that will convert it to C++ using IL2CPP, then to LLVM bitcode and finally to javascript using Emscripten. On the way the code will go through various optimization, obfuscation and validation processes.
Unity briefly explained the process and what IL2CPP and Emscripten here:
Unity blog: On the future of web publishing in Unity (Apr. 2014)
And here is the website of Emscripten

Build-Time Errors

For the first several build attempts, Mono and the Unity Editor thought our code was A-OK, but IL2CPP and Emscripten disagreed and produced an error instead of a build. If you’re experiencing something like this, here are some things I noted that may cause build-time errors:

Incompatible code for WebGL
Threading, basic sockets and other operations discussed in the previous chapter.

Incompatible plugins
It’s best to check with each plugin’s vendor whether or not their plugins were successfully tested with WebGL.

  • We had to upgrade Newtonsoft JSON
  • We had to discard usage of LOOM  because threads aren’t supported in-browser
  • Facebook’s SDK plugin was unsupported at the time. (Note Facebook has already provided an SDK that is stated to be compatible with WebGL, but it works only with Unity 5 –  Facebook SDK for Unity v7.0.2 Beta)
    More info here: Facebook SDK for Unity downloads

Player settings

You may encounter build errors due to using .NET directives which are not included in the .NET subset Unity packs with your game. If you’re seeing errors stating some symbols “Failed to resolve”, you may want to set the API compatibility to “.NET” (instead of Subset).
Read relevant Unity documentation for Player Settings

Incorrect Build-Window settings

Development build
I suggest not to build a development build on the first try, as these builds are bigger, less optimized and contain debugging related code (Larger files may cause browsers to bloat in memory).

Unity documentation for isDebugBuild

Optimization Level
It’s best to set “Optimization Level” to “Fastest (Very slow builds)”.
This can resolve browser crashes, and greatly enhance the performance of your game. There are also some reports online claiming this resolves certain build errors.
Just to compare, for Pirate Kings, “fast builds” took about 15 minutes, “very slow builds” take ~20-25 minutes.

Troublesome code that fails IL2CPP or causes IL2CPP to fail Emscripten

When we first ported Pirate Kings there was a specific code segment that crashed our build. Eventually, we figured out it was caused by a small C# part of our code that was a generic method with a new() constraint  (MSDN documentation for “new()”). Locating it required a lot of trial and error. Removing the specific new() constraint for WebGL resolved it. I also had to refactor any code in that method that relayed on the constraint as well.

I couldn’t find any reason why this specific method wouldn’t let the game build, as other similar methods with the same constraint and structure clearly didn’t cause any issues.
To-date, I’m assuming it was a fluke that caused either IL2CPP to produce invalid C++ code, or at least code that Emscripten couldn’t parse due to its own bug.

Update for our issue with generics:
I believe this to be related to instantiating generics while using an in-place initialization clause.

Code that crashes the build for me:

public void MyGeneric<T>() where T : BaseClass, new()
{
    var instance = new T { property1 = true };

Alternative code that manages to build successfully (Unity 5.1.0.f3):

public void MyGeneric<T>() where T : BaseClass, new()
{
    var instance = new T();
    instance.property1 = true;


If you were unfortunate enough to have build failures, here are some tips:

  • Use revision-control (we use Git)
  • Phase out portions of the code until the project builds to locate problematic code, use the revision control to help you track what you phased out and what you did not.
  • Start by removing external plugins that are not stated to be WebGL-compliant
  • Try various Unity 5 versions, always go for the latest you can possible get, but beware of preview releases – for us Unity 5.1 provided better results than the preview of 5.2 (Which caused a serious memory leak).
  • Don’t forget to check if you have the latest patch release for Unity from their patch-release page
  • Open the Unity log file and view the full build error, read about it in the Unity docs for paths and more info.
  • Look for similar errors in the Unity forums
  • Commits made for diagnosis should only contain your own changes, and not any automated upgrades or import-modifications by Unity.
  • If you still can’t build and you removed any 3rd party software, continue to investigate places that use LINQ and/or Generics, both of which proved to be problematic in WebGL

Build Results Overview

Unity bundles your game with a default HTML page, some Javascript code (not directly related to the game) and a few image assets. You can create your own template and configure Unity to use it, or simply replace these files manually after the build with your own.
* More detail in the next chapter; for now, I’ll quickly review the contents of the build product.

Index.html
The main page that contains the canvas HTML element that will display the game.

.htaccess
This is a web-server specific file, not related to the game directly and not always required (highly depends on which web-server you use to serve the game files).
You can read more about .htaccess files in the relevant Wikipedia page

Note: If you’re on a POSIX-compliant system (Linux, OSX, etc..) this file will be hidden.

TemplateData/ folder
This is part of the standard Unity HTML template for WebGL. It contains some image-assets for the index page and some Javascript code that configures the loader background and progress bar of the default page template.

Release/ folder
These are javascript and datafiles required to run your game. The “product” of the build.

Compressed/ folder
“Compressed/” contains a copy of everything in “Release/”, but compressed via gzip.
Unity literally just takes the content of “Release/” and compresses the files using 7zip.

Compression is an essential part of serving the game to the public; We’ll cover it in more detail in the next chapter which will discuss publishing the game.

Apart from the content of Release/ and Compressed/, Unity fetches the files from a built-in template. You can inspect the original template by locating it in your Unity installation directory.
For example here: Unity-5.1.2f1/Editor/Data/PlaybackEngines/webglsupport/BuildTools/
WebGLTemplates/Default/

But now is not the time to brand a web page. First, we want to verify that the build works.

Browser Adventure Time

For the first run, I wanted to see the browser can actually find this bulk of data to be a valid WebGL app.

Here is some useful information:

  • Google chrome doesn’t allow loading local WebGL apps, by default


    Here’s one guide
     for enabling loading html files from your local files instead of a web-server for Google Chrome
  • Google Chrome consumes a lot of memory when running a WebGL app, at least one produced by Unity
  • For the combination of Unity 5.2.0b3 and Google Chrome 44.x I observed some unexplained memory leaks and occasionally Chrome would turn into a memory bomb and even crash the entire OS (Windows).
  • Mozilla Firefox seems to have an easier time loading WebGL apps, at least ones produced by Unity.
  • Mozilla Firefox seems to require less memory (better memory management/GC?) for the game.
  • If you are loading the index page locally, or using an improperly configured web-server, you won’t be able to use the “Compressed” folder, only the “Release”

Naturally, because it’s Google Chrome that disallows the WebPlayer plugin, it was our main and sole target, but, for the very first few looks, I do recommend working with Firefox since it is a bit less strict.

Loading the game (using the default Unity template) should look like this:image00

 

At this point, I didn’t expect the game to run smoothly, but I did want to see the first scene displaying at the very least.I basically want an indication that the Unity engine code reached the point where the actual code of our game is ready to work. In other words, I want the progress bar to go all the way, see the Unity splash screen (a blue splash that shows after this loading screen) and see our first scene of the game.

 

Troubleshooting browser issues not related to our game code

If the build cannot reach the point where a scene starts loading and actual game code starts to run (due to a browser crash, a Javascript error or any other oddity), I recommend the following:

  • Looking at the browser console/log to check for errors
    1. Google Chrome – Using the Console
    2. Mozilla Firefox – Web Console
  • Make sure to set “Optimization Level” in the build settings to “Fastest (very slow builds)”
  • Make sure it’s not a development build
  • Make sure in the player preferences, under publishing settings, that you did not request too much memory. Pirate Kings uses 512mb and it works out just fine.
    For more information, see the “Player Settings” section here: http://docs.unity3d.com/Manual/webgl-building.html
  • For Chrome, navigating to chrome://gpu/ and checking the log for errors
  • There’s a “Rendering” tab starting of recent versions of the Chrome developer tools:
    image04

  • Trying with a different browser and observing if the same problem occurs
  • Reviewing your build settings and trying to produce another build
  • Trying to build with other Unity versions.
    Example: For me Unity 5.1.0f3 managed to constantly produce a working build, but Unity 5.2.0b3 occasionally didn’t. (Yes, occasionally.)
  • Seek insight in browser documentation
    1. Mozilla WebGL best practices
    2. Chrome developer docs

 

Questions? Comments? You are most welcome to post them!

 

Next chapter:

  • WebGL deployment considerations
  • Handling browser restrictions and resolving browser related issues
  • Understanding the WebGL HTML template and branding it
  • Publishing the game both to Facebook and to the web in general.
Lital Novosolov Natan

Unity client developer

4 Comments

  1. public void MyGeneric() where T : new()
    {
    var instance = new T();
    instance.property1 = true;
    }

    How can this ever compile if T is not constrained to anything (except the new() constraint) ??

  2. Chris B

    Great info. Looking forward to the next chapter as our target for our current game is Facebook and we need to get the webplayer build converted over.

  3. Sangpil M

    Great post. Did you guys have specific loading issues that happen only on Safari?

Leave a Reply