WebGL builds and unresponsive javscript

I have been experimenting with unity 5 and the new WebGL builds. In order to do this i downloaded the latest beta pro version of the pathfinding project in order to get it to work in the first place.

However i have been running into a problem for the specific platform. Whenever i generate my recast graph at the start of my level, the browser assumes that unity has “locked up” and starts throwing unresponce script error at the user. Prompting them to stop the game/code.

Looking for the problem i figured out that the code just simply “takes to long”. Due to many compromises already being made to work for all the different platforms we deploy on, i am not willing to tune down the graph to get a faster build time either.

The generation code for some reason does not use coroutines. Changing the code to a coroutine helps inmensly (in that it works in WebGL, and doesn’t lock up the code) but causes nullpointers all over due to the code expecing the graph creation to be “done” after it was called.

My suggestion is that the graph scanning code starts using coroutines in order to prevent WebGL from locking up on it. (which happens really cast i might add). And using a coroutine whould be better in general, unless a seperate thread is available to the user (which WebGL does not support).

Any ideas on this and/or if this is going to happen at all?

Thanks in advance,
Vince

Hm… That was unexpected.
I am not completely sure how System.Threading.Thread.Sleep is translated to javascript, but you can try running

AstarPath.active.ScanLoop ((p) => {
   Debug.Log ("Scanning...");
   System.Threading.Thread.Sleep (1);
});

And disabling Scan on awake.

Alternatively rewriting the ScanLoop method to a coroutine should work as well. Pathfinding should be blocked while that runs, regardless of if it is a coroutine or not.

Also, you might want to try caching your graphs. See http://arongranberg.com/astar/docs/save-load-graphs.php

Well threading seems to be not supported AT ALL in javascript. So i doubt the thread sleep will do a whole lot. Not sure about where that exactly is anyway.Currently i have the ScanLoop method changed to a coroutine. Also, the map is generated at runtime, so caching graphs is sadly not an option. I wish it were that simple though!

Due to the nature of the long process i also made the RecastGenerator.ScanAllTiles method a coroutine to be able to yield return inside the tile generation for loop. This caused me to write all the way up to ScanInternal, making those ALL coroutines (everything in between! look it up it’s like 3 methods and then through the base class etc. quite a mess)

It seems to work… almost. But at the end of the whole thing i get an error on AstarPath.InitializeNode (it throws that exception there) that somehow it tried to initialize a node when something was locked/busy, i am not sure what since most of the thigns in that statement go into the magical world of threading (which is disabled at this point).

So at this point i am not sure where to go. I am fearing that the project is going to fail if i cannot resolve this issue. But i just can’t get it to play nice with the coroutine. If you have any idea what is going wrong, i would like to hear it.

EDIT: I would like to point out that it starts going wrong inside RecastGenerator.ScanAllTiles upon calling BuildTileMesh();
It crashes in there with the InitializeNode thing. Hope that helps?

EDIT2: The method should work exactly the same being a coroutine, i do not get this at all. I made sure i used Yield return startCoroutine as well. I am at a loss.

EDIT3: More testing shows that this only goes wrong after 118/119 out of 256 tiles. I am not sure if something is on a timer or on a wait, but that doesn’t make a whole lot of sense.

EDIT4: It seems to break in RecastGenerator.CreateTile, in the loop where the comment reads: //Create nodes and assign triangle indices
on this loop it has more then 0 length, and then crashes on creating the TriangleMeshNode. Any idea why this is?

Hm, I think I know what it is.
During Update(), the AstarPath class will run PerformBlockingActions to process any graph updates and similar, however after that it will always unblock the pathfinding, which obviously will cause problems if you are scanning at the same time.
So I think that you should try to put the contents of the Update method (in the AstarPath class) inside an if checking for if isScanning is false.

Sure, but Thread.Sleep could still be implemented in a reasonable way. See https://github.com/kripken/emscripten/wiki/Asyncify

However after testing it, it just seems to hang the browser unfortunately…

For my case i use RecastGraph, and it seems that doing this, and doing the same thing inside RecastGenerator.OnDrawGizmos() works for now. I am going to make a WebGL build now and hope for the best.

Ok, so after testing we have made the following discoveries:

  • We can’t seem to build with navmesh enabled but Exception catching off.
  • Wish Exception catching on full, the functionality is fine
  • Loading time from the game went from 20 seconds to 5 minutes and 40 seconds
  • 5 minutes of said loading time is navmesh generation in WebGL
  • path calculations went from 5ms tot 50ms averages on WebGL as well (not that bad in usage though)
  • Multiple seekers on the navmesh calculating a path every 0.5 seconds (to find an exit it checks every so often gets very very very slow. We assume this might be debug logs about those paths being recalculated. But we have not tested this further.

We hope you can ammend these problems in the future, so please keep us up to date with any developments in this area or any suggestions you might have to improve on the code.

As for the changes we made to make the generation work for us on WebGL, if you are interested we can send you the files as is, since they are your classes, we assume you know what to do with them from that point.

Thanks in advance!

Yeah, this should definitely be improved if turning on exceptions is that slow.
Is it possible for you to see what exceptions cause it to fail? I cannot think of any exceptions that happen when scanning the graph.

Thank you. The files would be really helpful.

It is not so much having that the slowdown is caused by exceptions being ON in WebGL, but i cannot measure it when it is off. So we don’t have any proof if that is the cause or not. I expect much of the slowdown just to be from WebGL in itself (C# to C++ and then to JavaScript can’t be good for any big codebase.)

The point of exceptions being off is… that you cannot catch the exceptions. So we have no idea either as to why it crashes when it is turned off. I would like to reffer to the following post about the future of this:
http://forum.unity3d.com/threads/webgl-exceptionsupport-performance.307713/

As for the exception on/off thing, i cannot find the exact post. But it seems to be common for exceptions ON == nothing is wrong. And exceptions OFF == some error/exception that crashes it which is not catched. It is pretty horrible at this moment.

As for the edited code:
http://pastebin.com/BXJvgxxz
http://pastebin.com/a02cqRwC
These will expire in 1 day, please make a local copy.
The original code was taken from the latest beta (3.6.4)
If i missed anything, just assume i made void into IEnumerator and started a coroutine

Oh you measured in the editor vs webgl. Yeah, that could be a big difference.
Try firefox btw, I think their ASM.js execution is faster.

According to the thread at least Unity 5.1 will improve things.

Yeah, i hope 5.1 will fix things. But i cannot wait for that to resolve itself, as of now we are looking into alternative methods for pathfinding.

We are already running it in firefox for other reasons at any rate, but i was measuring the android build on a low-end ish device, to WebGL. So that puts those numbers into perspective a bit.