Wie in meinem letzten Beitrag beschrieben macht es Unity Hobby-Entwicklern ziemlich schwer, Online-Spiele zu entwickeln. Einen mit Unity erstellten Game-Server auf einer Amazon AWS-Instanz zu betreiben ist dank fehlender Batchmode-Option unmöglich. Als Workaround habe ich für mein aktuelles Projekt einen eigenen Relay-Server implementiert, der auf Basis von Websockets arbeitet und so das Betreiben eines eigenen Servers ermöglicht kombiniert mit den Vorzügen eines Servers in der Cloud mit fester IP-Adresse.
Um ein eigenes Online-Spiel für wenige Spieler zu testen eignet sich die Amazon Cloud (AWS) hervorragend. Eine Instanz in der „Elastic Compute Cloud“ (ec2) gibt es ein Jahr lang kostenlos und kann mit unterschiedlichen Betriebssystemen wie Windows Server 2012 oder Ubuntu betrieben werden. Mit einem Game-Server auf einer solchen Instanz ließe sich das Problem des NAT-Punchthrough, also der Port-Weiterleitung hinter einem Heimrouter, umgehen. Dieser führt nämlich meistens zu Problemen wollte man einen Server bei sich zuhause betreiben.
Leider haben diese Server-Instanzen ein gravierenden Nachteil: sie besitzen keine Grafikkarten, sodass sich mit Unity erstellte Programme nicht starten lassen. Abhilfe könnte der Batchmode von Unity schaffen, doch ist dieser ein exklusives Feature der Pro-Version. Als Alternative kämen beispielsweise die neuen Unity Internet Services in Frage. Diese bieten eine Lobby und einen Relay-Server, sodass sich Spieler in einem Multiplayer-Spiel verbinden und selbst als Server fungieren können. Allerdings ist dieser Service nur im derzeit laufenden Beta-Stadium kostenfrei und für Nutzer einer Personal-Lizenz nutzbar. Welche Kosten nach der Beta-Phase entstehen ist ungewiss.
Mit diesen Einschränkungen im Hinterkopf habe ich also eine andere Lösung gewählt, und zwar einen eigenen Relay-Server der auf meiner ec2-Instanz läuft, und zu dem sich sowohl Game-Server als auch die Spieler-Clients verbinden. Das WebSocket-Protokoll bietet den enormen Vorteil, dass es über die http- bzw. https-Ports 80 bzw. 443 läuft, die auf allen Heim-Routern und Mobilgeräten standardmäßig freigeschaltet sind. Schließlich will jeder Webseiten in seinem Browser ansehen können. Das Problem des NAT-Punchthroughs entfällt also.
Was genau macht nun dieser Relay-Server? Er empfängt eine Verbindungsanfrage von einem Game-Server, der z.B. bei mir zuhause läuft. Er legt die Verbindungsdaten in einer neuen Session ab und wartet dann auf Anfragen von Spieler-Clients. Sobald sich ein Client mit dem Relay-Server verbindet, wird dem Game-Server dies mitgeteilt. Sowohl Game-Server als auch Clients senden nun ihre RPCs an den Relay-Server, der diese jeweils weiterleitet. Und hier wird es nun aufwändig, denn natürlich lassen sich die RPC- und Synchronisationsmethoden der Unity-Netzwerkschicht nun nicht mehr verwenden. Die RPC-Funktionalität muss man selbst implementieren.
Eine Implementierung des WebSocket-Protokolls in C# ist websocket-sharp und kann bei GitHub heruntergeladen werden. Die zugehörige DLL lässt sich mit Visual Studio einfach kompilieren und in das eigene Unity-Projekt integrieren. Dazu schiebt man die entstehende Datei in das Plugins-Verzeichnis unter Assets. Die in websocket-sharp enthaltenden Beispiele eignen sich hervorragend als Einstiegspunkt für den eigenen Relay-Server.
Zwei Dinge gibt es noch zu beachten:
- Websocket-sharp greift auf die Socket-Implementierung im Namespace System.Net.Sockets zurück, welcher in Unity 4.x auf Mobilgeräten geblockt wird, sofern man keine Pro-Lizenz besitzt. Die einfachste Lösung dafür ist natürlich auf Unity 5.x umzusteigen. Sollte das nicht möglich sein, kann man einen Blick auf das Asset-Paket Good ol‘ Sockets werfen, das die Socket-Funktionalität für Unity nachimplementiert. Ich habe es selbst allerdings nicht ausprobiert, sondern die einfachere Variante gewählt und auf Unity 5.0 aktualisiert.
- WebSockets sind eine Erweiterung des Http-Protokolls. Leider versteht nicht jeder Proxy-Server im Internet diese Erweiterung, wie in diesem Beitrag von Robert Hekkers beschrieben wird. Auch bei manchen Mobilfunk-Providern mag das der Fall sein, sodass die WebSocket-Lösung möglicherweise nicht auf allen SmartPhones funktioniert. Die allgemein vorgeschlagene Lösung ist, anstatt Port 80 den Port 443 zu verwenden, selbst wenn man keine Verschlüsselung nutzt, da dieser häufig nicht über einen Proxy läuft. Websocket-sharp unterstützt auch das.
Will man tatsächlich ohne jegliches Budget ein Multiplayer-Onlinespiel, insbesondere für Mobilgeräte, entwickeln so ist der vorgeschlagene Weg sicherlich eine Option. Ich hoffe, dass ich die Zeit finde meinen eigenen Relay-Server in eine präsentable Form zu bringen sodass ich ihn hier demnächst veröffentlichen kann. Solltest Du Interesse daran haben würde mich eine Rückmeldung freuen und das natürlich meine Motivation steigern.