31 January 2016

Forwarding trigger events

Sometimes when developing any kind of game you want to have a function called on an object A (not necessarily a GameObject) when object B hits a trigger defined by object C. For example, A can be your game controller, B your player's avatar and C a trigger next to a door. When the avatar walks into the trigger you want to call something like

GameController.Instance.LoadLevel("nameofthelevel");

So you write a "DoorTrigger" monobehaviour with a public string member for the name of the level that should be loaded when the avatar walks into the trigger. Perfect.

The things is that this is a very common behaviour; often you just want to call one simple function on another object when the player (or something else) runs into a trigger and often the trigger object and the callee for the function is not the same object. Writing a new class for every occasion is cumbersome.

In the UnityEngine.UI namespace we have the EventTrigger class that solves exactly this issue, but then for input events. When a ui button is clicked the code for doing something with that event is often not in a monobehaviour on that button, but likely in some PanelController class that controls the panel. So you use the button's functionality to forward the event to that controller. The EventTrigger class does the same thing for other ui objects than buttons.

So we thought to take a peek at the open source implementation of EventTrigger and see if we could mimic the same easy editor interaction for physics trigger events. We finally came up with a class called ForwardTrigger that can be found here. It is very similar to the code of EventTrigger but a lot less complicated, since we don't have to deal with InputModules but simple trigger events.

We introduced a PhysicsTriggerEventData class that tells you what object the trigger was and what object the collider was. We also copied with very little changes the code of the editor for that class so that we can now forward physics trigger events as easily as we could forward click events:

A working example is hosted on this bitbucket repository called "UnityToolset". This repository will become the place where I'll add all code that I frequently use in multiple Unity projects (as long as it is not under NDA) and also all code that I write about on my blog. I welcome all feedback on this project!

06 January 2016

Unity crash dumps to the rescue!

My last post ended with me being disappointed about the state of our webgl build of Kweetet. I'm happy to say that I solved a lot of the remaining issues in the past holidays, against my expectations! The WebGL build might be a viable production target after all.

Nevertheless we still need a standalone build, because it's clear that WebGL is not fit for older systems. The memory usage has become less (around 1GB) but it's still a lot and we have a target audience that sometimes has only that.

Creating a standalone version went fast, i was done in a day, but that doesn't come as a surprise since standalone windows and webplayer builds are very alike.

A colleague of mine always had the weirdest crashes in the webplayer. It was always only on her pc and we could never reliably reproduce it. The log of the webplayer pointed in various directions, but we could never determine the cause of the crashes. Now with the standalone build she had the same crash and behold: there was a crash.dmp file! I've always made builds for mobile and web platforms so I had no idea that standalone build generated dump files. I opened it in Visual Studio immediately. I couldn't do much with it at first, but googling around brought me to this thread on the Unity forum where I learned that Unity has a symbol server! There you can download the pdb files for a standalone build, or even better, you can add the server to your debugger settings in Visual Studio:

Once you've done that you have an accurate callstack of the crash. The callstack was completely different than anything reported in the webplayer log files, but it explained completely every crash my colleague has had. It was an easy fix after that.

Trying to reproduce hard to find crashes in the webplayer or even the webgl builds with a standalone build can really pay off.

22 December 2015

The quest for WebGL - part 3

Find part 1 here. Find part 2 here.

So we have our semi-working webgl build. I still had to re-enable parts of the code that I commented out, so the adventure isn't over yet :)

A bug with RawImage

In our dialog system we use images to represent the player and the NPC's talking to each other:

But on the webgl build the scale of the images were completely wrong. I made a separate project and could reproduce the problem, resulting in a bug report that the QA people of Unity could confirm:

In the code we assign a texture to a RawImage object and then call "SetNativeSize()", but as you can see this doesn't happen correctly in a WebGL build. See here for the development on that. In the meantime I changed the code to use an Image instead of a RawImage. Instead of a texture for the RawImage, we now need to create a sprite from the texture and assign that to the Image which works, so I'm in the clear for now.

The battle with memory

Our game is a memory hungry monster, when we load the first scene Firefox takes +/- 1.8GB of memory! And that's without the asset bundle memory leak problem from my previous post. That problem has been solved since 5.2.3p1, but it appears that there are still some issues, the memory doesn't leak anymore, but it still takes a lot; Firefox goes to 3GB when we load the assetbundles in the cache. In other words, not usable yet.

So obviously a lot of memory is going to the assetbundles, but how much? Why? And where does the rest go to? I asked on the Unity forum for some leads on this. I learned that surfing to "about:memory" in Firefox gives you a complete breakdown of its memory use, cool! But apart from "a lot of memory goes to javascript handling" I learned nothing useful from that.

To limit the javascript impact on memory it is key to have as little code as possible, and certainly to have very few to no plugins, since they can drag in a lot of .Net code that you don't even use. We removed the UniWeb plugin from our game, since we don't use it in the webgl build and the uncompressed development build size went from 195mb to 119mb! That didn't translate to a big difference in Firefox' memory abuse though.

Audio

Audio seems to be an issue by itself on WebGL. As the manual clearly states, audio is handled completely different compared to the other platforms, and unfortunately it shows. In your project, if you use wav, mp3 or ogg exports of the same audio file, they should all sound the same, which they do in the editor, windows standalone and webplayer builds, but in WebGL there is a difference between the three! I found that mp3 files are best when targeting WebGL, but it still strikes me as odd why there would be a difference since they are all converted to AAC.

5.3.x headaches

And then finally Unity 5.3.0f4 was released! Hurray! Lots of fixes and improvements!

Or at least that is what was promised, but it was the opposite.

Conclusion

So that's it. I got until the end of the year to create a decent WebGL version, but because of all the bugs in Unity (most not even WebGL related) I cannot in good conscience declare that I have a WebGL build that is remotely ready to go to the production branch. I'll have to abandon this endeavor and instead we'll create a standalone build with an installer and hope that users will not complain too much about that.

I hope I find time here and there to continue because I still believe it should be possible, but first Unity will have to get their shit together. Where Unity 4 was a stable engine, Unity 5 is biting your nails every time there is an update and hoping nothing obvious went broken.

So I'm a bit disappointed yeah.

18 November 2015

The quest for WebGL - part 2

Find part 1 here.

So now that we have a +/- working version running with Unity5 it was time for the next step: making a webgl build. That wasn't hard, getting the build to run on the other hand was.

1. Communicating with the api

You can't start Kweetet unless you're logged in, so one thing that we needed to get working first was the communication with the api. We used sockets in the webplayer with the UniWeb plugin, but as you might know sockets aren't supported in webgl, so we had to look for other solutions. Our website had a javascript class that already communicated with the api via CORS for other purposes than the game, so we wrote a javascript plugin that uses this class. The documentation on how to do that can be found here, but what's missing is how to use callbacks. Our function needs to call the api and trigger a succes or error callback. It ended up looking like this:

var WebGLAPI = {
  $callbackObject: {},

  InitRestClient: function(successCallback, errorCallback)
  {
    callbackObject.successCallback = successCallback;
    callbackObject.errorCallback = errorCallback;
  },
  
  DoJSCall: function(path, method, data)
  {
    DK.restClient.doCall(Pointer_stringify(path), Pointer_stringify(method), Pointer_stringify(data), function() {
      var returnStr = arguments[0];
      var buffer = _malloc(lengthBytesUTF8(returnStr) + 1);
      writeStringToMemory(returnStr, buffer);
      Runtime.dynCall('vi', callbackObject.successCallback, [buffer]);
      _free(buffer);
    },
    function() {
      var returnStr = JSON.stringify(arguments[0].data);
      var buffer = _malloc(lengthBytesUTF8(returnStr) + 1);
      writeStringToMemory(returnStr, buffer);
      Runtime.dynCall('vi', callbackObject.errorCallback, [buffer]);
      _free(buffer);
    });
  }  
};

autoAddDeps(WebGLAPI, '$callbackObject');
mergeInto(LibraryManager.library, WebGLAPI);

As you can see we need to define a callbackobject where we register our callbacks in an init function. In the C# part that looks like this:

public class JsApiComm {
  [DllImport("__Internal")]
  private static extern void DoJSCall(string path, string method, string data);

  [DllImport("__Internal")]
  public static extern void InitRestClient(Action<string> success, Action<string> failure);

  [MonoPInvokeCallback(typeof(Action<string>))]
  public static void SuccessCallback(string arg)
  {
    ...
  }

  [MonoPInvokeCallback(typeof(Action<string>))]
  public static void ErrorCallback(string arg)
  {
    ...
  }

  public JsApiComm()
  {
    InitRestClient(SuccessCallback, ErrorCallback);
  }
  
  ...
}

Just today I stumbled upon a subtle problem with the code from the manual: to create the buffer to write a javascript string into, the manual uses the length of the string to create a buffer of that many bytes + 1. But if the string contains multibyte characters as in for example "Dieriƫ" then you need to allocate more bytes than characters, or you have a buffer overflow!

The javascript function writeStringToMemory does not look at the size of the buffer so if the string is larger than the buffer it simply writes outside of it. This of course caused many seemingly random crashes in our game, which made it difficult to find the cause at first. The solution is using the function that counts the bytes in the string, and thus enables us to create a buffer of the correct size. I mentioned this on the forum and they're updating this.

2. Memory leak

So with the api in place we can start the game, but even before the first loadscreen was done the browser ran out of memory. I had this in a latest version of Firefox 32bit and it was even worse in Chrome (Chrome has proven to be very bad at most of the things I tried). I then installed a 64bit developer edition, since that one would be able to go beyond 3GB memory and it did: the memory consumption went up to 10GB (!) and kept rising.

This turned out to be a Unity bug in WWW.LoadFromCacheOrDownload that we used all the time. It was this explanation of Jonas Echterhoff that tipped me in the right direction. A must read!

So we temporarily use the regular WWW download and now the memory leak issue is gone. It's supposed to be fixed in 5.3 so I'll try again then.

3. "Could not produce class..."

Another hard to solve problem was that our game crashed when loading a new scene with LoadLevelAsync. Apparently (thanks Marco Trivellato) this is caused by the stripping of classes you never reference in your code but do use in your scenes that you then load via assetbundles. You know you have this issue when you start seeing log entries that look like "Could not produce class with ID xxx". This gives you an ID which you can use to lookup here. For example, we had a few WindZones with ID 182 in some scenes that caused this issue.

4. Development vs Release build

With a development build it's easier to read stacktraces which you need to fix bugs, but most browsers aren't capable to handle the large output of that build (a .js file of 192MB!). Firefox 32 bit tries and succeeds most of the time, Chrome gives up before it executed anything. So I really recommend using the 64bit developer edition of Firefox, that one can handle any build, no matter what I enable or disable.

Luckily, chrome can run a release build, so we're in the clear. But it's still not as fast as Firefox.

Once these issues were solved we finally have a running build! Hurray! I commented out some parts of the game however to get this far, so I have to re-enable those en see what errors I need to fix there. But I'm cautiously confident that we'll succeed to port our game to webgl, how cool is that!

17 November 2015

The quest for WebGL - part 1

Because of the deprecation of plugins on first Chrome, then Edge and now even Firefox we are forced to convert Kweetet to Unity 5 so we'd be able to create a WebGL build. In the hope that a WebGL build will even work, that is, because WebGL isn't nearly as powerful as a plugin can be (yet - That's why I don't understand why browsers deprecate plugins without providing a decent alternative. Sure, in the future WebGL will be brilliant, I believe that too, but what about the present?).

To start we had to do some preparations, first one: convert from NGUI to the new Unity UI. The reason is simple: the less code there is in the webgl build, the smaller it will be and the less errors there can be. so we're working to ditch all big third party libraries and use the "native Unity" ones.
This step went fairly easy; NGUI is very similar to the Unity UI so the conversion was easy. There are a lot of improvements that made our life even easier than before.

The second step then was to actually make sure the project works in Unity 5 (the NGUI conversion was done in 4.6.x). This conversion was, in short, "less smooth".

Don't get me wrong, I'm a big fan of Unity and I understand most of the decisions they've made when changing Unity so I'm with them all the way, but I feel that they are rushing Unity 5 a bit too hard. The features they introduce or change have many bugs and are sometimes badly documented. After a month's worth of work we didn't have a stable version of the game at all. We still have the 4.6.8 branch though, so we can continue to develop, but the 5.2.x version has many issues. Positive is that forum posts get answers quickly from the Unity crew and things are getting fixed.

My intent is to document as much as possible all issues I encounter and what I did to solve them, in the hope that this is helpful for others. I want to do this as I go along, since the issues remain fresh in memory when I write this, so this will be a post in multiple parts.

1. Perforce

We use the P4Connect plugin from perforce itself, version 2.6. This is a 32-bit version we needed to upgrade, the latest version is 64bit compatible but doesn't work at all; it keeps losing the perforce connection when pressing play or other actions in the editor, rendering it completely useless.
This is not a Unity feature you say? I agree, but the only reason we use the P4Connect plugin is because the default perforce integration in Unity isn't working either, or at least never did for me. For example, P4Connect checks out every file you youch, together with the meta file and it even moves files in perforce when you drag them in the editor. The native perforce integration did not do this. At the moment we got it up and running with the 2015.2 version. The currently latest 2015.3 version however is not capable to create a correct connection with the server, so don't get that one.

2. VSTU integration is/was broken.

Microsoft and Unity announced together that Unity has now VSTU integrated. I was very happy to hear that because I'm an avid user of that plugin. But I was very disappointed of how the result turned out to be. There are numerous bug reports on this matter, for example here and here. Since the 5.2.2 version things stabilized a bit, but it's not as good yet as it used to be. For some reason the project needs to reload very often, setting up a new perforce connection every time that happens and resharper re-parsing all files anew. This wasn't the case with the old VSTU.

3. Asset bundles have changed - a lot

The folks at Unity clearly saw that many people created complex assetbundle creation setups for their games, so they came to help and created one of their own that would cover most use cases. It took me quite some time to convert our system to theirs. They did similar things as we did, but at first the new system was badly documented. Now they created a magnificent sample project and extensive documentation. Things would have been easier if I had it at the start :)

It surprised me a bit how much the system had changed, because I didn't feel the need. It is now supported to define assetbundles in the editor, but for a big production I cannot see that as feasible. Manually assigning the correct assetbundles for each asset in the game sounds like a tedious and very error prone work.

At Unite Europe 2015 there was a presentation about asset bundles, very interesting and very similar to our own system, but alas only applicable to Unity 4.x. A bit weird to see that presentation there while everything else was about the new Unity 5.

Next post I'll elaborate on our webgl version.