Adventures with Unity3d Web Player and socket.io
I am currently building a multi-player game with Unity3d, ES6 and socket.io. I had a LOT of challenges getting this all to work, in particular I had problems with the Unity web player’s security sandbox approach and included libraries. I’m dumping my pain and learnings into this article both for my own reference and hopefully to help some folks out there who wish to pursue a similar approach and have similar challenges
The Server- Node
- socket.io (1.3.6)
- ES6 + Babel + Gulp
The Client- Unity3D (5.1.2f1 Personal)
- unity-socket.io (https://github.com/fpanettieri/unity-socket.io)
I chose this project by Fabio Panettieri because it is well written, uses websocket-sharp and supports the newer Socket.io 1.0 protocol which a lot of the other libraries don’t.
RationaleThis is a bit of an odd combination I guess but I’m really into ES6 right now and building the game backend in ES6 felt natural and fluid. The Unity front end is a necessary evil because, well it needs to look like a game or nobody is going to play it. I guess I could do the same thing with Angular2 and canvas but Unity3d is the for-purpose-and-free tool for games, it’s fast and c# is not too horrible.
Ultimately this game will probably go to Steam using a desktop client but I am targeting the Unity web player because in the Alpha stages, I just wanted folks to hit a web page and play. Here is where my problems began.
Web Player Problem 1 - Getting it to BuildFlipping from standalone mode to web player mode (file -> Build Settings -> Web player) immediately breaks the build of game due to compilation issues in the the websocket-sharp library. After digging around, I ended up following the dubious example set here (https://github.com/sta/websocket-sharp/issues/52) and manually hacking the websocket-sharp code so that it would compile. I wasn’t happy with this approach but I seemed to be mostly hacking out stuff that wasn’t needed so I just kept hacking until it compiled.
Note that obviously this approach assumes you have pulled in the whole socket.io folder into your assets folder including all the SocketIOComponent stuff and the websocket-sharp source also. Some folks suggested to build the library separately outside of Unity and then just import the DLL’s. I could not get this to work, the compiled dll’s were not compatible with unity-socket.io. In hindsight this may have been a versioning problem, not sure.
Web Player Problem 2 - Sandbox SecurityAfter getting the game to build correctly, the game appears to work from the unity editor but after packaging and running the game from a test page, it fails with the following error:-
Unable to connect, as no valid crossdomain policy was found
This was difficult to track down and fix but this page (http://docs.unity3d.com/Manual/SecuritySandbox.html) was a great reference and helped a lot (RTFM). The first key to figuring this out is to change the editor setting to emulate the web player behaviour in the editor, this makes it much easier to reproduce and debug. Do this by choosing Edit —> Project Settings —> Editor and fill in the WWW Security Emulation box. I used this url (http://localhost:10090/mygame.html) because I was serving my socket.io from 10090 but I think only the host/port is important.
A couple of notes on the debugging:-
- Using the emulation mode puts the errors in the Editor.log (~/Library/Logs/Unity/Editor.log on OS X) see this link for details (http://docs.unity3d.com/Manual/LogFiles.html)
- I didn’t find the Debug setting (ENABLE_CROSSDOMAIN_LOGGING 1) to be very helpful but try it if you want
- I could NOT get Security.PrefetchSocketPolicy() to work. Supposedly this allows you to set up the socket security handshake on a port other than the default of 843. I ended up using the default port but this was ok because on my host (digital ocean) I have have no problem with admin access (I think you need admin access to serve on ports lower than 1024).
- Definitely use the telnet method (under the Debugging section of the above article) to check that your security handshake is working. If the telnet doesn’t work, your web player won’t be able to connect either.
Socket Policy Server - The last piece of the puzzleThis very helpful github issue (https://github.com/sta/websocket-sharp/issues/59) was the key to solving the security issue to quote… “You need a Socket Policy Server”. I had tried several different ways of serving out the policy file from within my existing node server (and this might still be possible) but in the end, I decided to use a standalone policy server.
I used the project from here (https://github.com/bichinger/nodejs_socket_policy_server) but I had to hack around with it to get it to work. You might have better luck with the ‘out of the box’ version but if not, here’s what I did to it:-
- Stripped out all of the startStopDaemon stuff in favour of a custom upstart/forever config (see below) because that is the standard approach for all my node projects
- Stripped out all of the Global Config stuff because It was annoying and I couldn’t get it to work.
So after setting up my socket-policy-server to run, the game was now able to connect to the server and the game works! Despite all of the hassles, I still think this is a good stack for this type of application.