Wie schreibe ich ein Netzwerkspiel? [geschlossen]

73

Basierend auf Warum ist es so schwierig, ein MMO zu entwickeln? :

Die Entwicklung vernetzter Spiele ist nicht trivial. Es gibt große Hindernisse, die nicht nur bei der Latenz, sondern auch bei der Betrugsprävention, der Statusverwaltung und dem Lastenausgleich überwunden werden müssen. Wenn Sie keine Erfahrung mit dem Schreiben eines vernetzten Spiels haben, wird dies eine schwierige Lernübung sein.

Ich kenne die Theorie über Sockets, Server, Clients, Protokolle, Verbindungen und dergleichen.

Jetzt frage ich mich, wie man lernen kann, ein Netzwerkspiel zu schreiben:

  • Wie können Lastprobleme ausgeglichen werden?
  • Wie verwalte ich den Spielstatus?
  • Wie halte ich die Dinge synchron?
  • Wie schützt man die Kommunikation und den Client vor Reverse Engineering?
  • Wie kann man Latenzprobleme umgehen?
  • Welche Dinge sollen lokal berechnet werden und welche Dinge auf dem Server?
  • ...

Gibt es dazu gute Bücher, Tutorials, Sites, interessante Artikel oder andere Fragen?

Ich suche nach umfassenden Antworten, aber bestimmte sind auch in Ordnung, um den Unterschied zu erkennen.

Tamara Wijsman
quelle
4
Ja, es gibt Bücher, Tutorials, Websites, interessante Artikel und andere Fragen dazu.
Ricket
2
Ich habe Bounty hinzugefügt, um die Frage zu pushen, ohne sie zu ändern, und Benutzern einen Grund zur Beantwortung zu geben, da diese Frage Antworten verdient. Auf diese Weise erhält der beste Beantworter den Ruf für seine Arbeit, aber es gibt keine einzige Antwort, die die Frage beantwortet.
Tamara Wijsman

Antworten:

61

Zusätzlich zu dem Artikel, der in anderen Antworten verlinkt ist, kann ich etwas über die Erfahrungen mit dem Arianne-Projekt erzählen .

Wie halte ich die Dinge synchron?

Wir haben das Framework „ Marauroa “ um das Konzept der Handlungen und Wahrnehmungen herum aufgebaut: Handlungen werden vom Client an den Server gesendet und tragen Benutzereingaben wie (gehe nach links, greife Monster # 47 an, sag 'Hallo'). Und vom Server werden Wahrnehmungen an die Clients gesendet, die ihnen den Zustand der Welt nahebringen. Diese Wahrnehmungen werden jede Runde gesendet. Je nach Spiel verwenden wir Rundenzeiten von 30ms bis 300ms.

Wir haben zwei Arten von Wahrnehmungen : Eine vollständige Wahrnehmung wird beim Anmelden gesendet und wenn der Spieler einen neuen Bereich (Zone) betritt. Danach werden unterschiedliche Wahrnehmungen gesendet, die nur die geänderten Attribute (z. B. Position) der geänderten Objekte und natürlich neue und entfernte Objekte enthalten.

Wie kann man Latenzprobleme umgehen?

Wir sind fest davon überzeugt, dass der Server immer richtig ist. Der Klient macht einige Vorhersagen wie reibungsloses Gehen, Kollisionsprüfungen und so weiter. Aber wenn ein Client und der Server sich nicht einig sind, gewinnt der Server. Das Teilprojekt Stendhal (ein 2D-RPG) verwendet standardmäßig eine Umdrehungszeit von 300 ms (mit viel Glättung auf Client-Seite). Dies macht Stendhal sehr widerstandsfähig gegen Verzögerungen.

Hinweis: Einige andere Spiele vertrauen dem Client in gewissem Umfang, um die Auswirkungen von Netzwerkverzögerungen zu minimieren. In WoW wurde es oft auf einem Schlachtfeld namens "Warsong Gulch" ausgenutzt. Es gibt zwei Möglichkeiten, die ein Spieler mit der Flagge wählen kann: In der Mitte durch einen Tunnel und auf der rechten Seite den Berg hinauf. Ein betrügerischer Spieler rennt in Richtung Tunnel und verursacht dann für sich selbst eine Verzögerung. Der Server und die anderen Clients sehen ihn weiterhin auf sich zu rennen. Aber nach einiger Zeit kann dieser Client dem Server mitteilen, dass er in Richtung des Hügels gegangen ist. WoW prüft, ob der Abstand zwischen den zuletzt übertragenen und den aktuellen Koordinaten zum Zeitsegment passt und akzeptiert dies.

Verwendung von UDP vs. TCP

In früheren Versionen haben wir UDP verwendet, um den Overhead von TCP zu reduzieren. Verlorene Pakete haben wir selbst gehandhabt. Dies hat zu Beginn des Projekts perfekt funktioniert. Aber als der Server vor einigen Jahren von einer DSL-Heimverbindung in ein richtiges Rechenzentrum verlegt wurde, gab es große Probleme. UDP ist (oder war vor mindestens 5 Jahren) extrem anspruchsvoll in Bezug auf die CPU-Leistung von Firewall-Hardware: Der Regelsatz muss auf jedes einzelne UDP-Paket angewendet werden. Für TCP wird der Regelsatz jedoch nur für die ersten 3 Pakete angewendet. Danach ist die Verbindung hergestellt. Alle folgenden Pakete umgehen den normalen Regelsatz, weil sie sich in der Verbindungstabelle befinden oder weil sie kein SYN-Flag haben.

Wie schützt man die Kommunikation und den Client vor Reverse Engineering?

Arianne ist komplett Open Source, dazu gehören Client, Server, Grafik, Musik. Dazu gehören natürlich auch unsere Protokolldokumentation und sogar ein Analysator, der zum Debuggen verwendet wird.

Es ist einfach, die Kommunikation mithilfe von SSL gegen unbefugtes Abhören durch Dritte zu schützen.

Ein Schutz gegen Reverse Engineering ist jedoch nicht möglich. Sicher können Sie es verschleiern und Anti-Debugging-Techniken verwenden. Letztendlich können Sie jedoch ein Reverse Engineering von Software, die Sie an Benutzer weitergeben, nicht verhindern. Es gibt eine sehr interessante Präsentation darüber, wie Skype rückgängig gemacht wurde, obwohl die Entwickler sich sehr um Anti-Debugging-Techniken bemüht haben: http://recon.cx/en/f/vskype-part1.pdf

Hinweis: In einigen Ländern ist das Reverse Engineering illegal oder es ist zulässig, einen Absatz in die Lizenz aufzunehmen oder das Reverse Engineering zu verbieten. Es gibt jedoch auch andere Länder (wie das Land, in dem ich lebe), die ausdrücklich das Reverse Engineering im Zusammenhang mit der Entwicklung kompatibler Datenspeicherformate oder Übertragungsprotokolle zulassen, Absätze in der Lizenz oder Nutzungsbedingungen, die versuchen, dies zu verbieten, sind ungültig. (Alles in diesem Abschnitt ist, soweit ich weiß, kein Anwalt.)

Welche Dinge sollen lokal berechnet werden und welche Dinge auf dem Server?

Wir berechnen alles, was mit der Spielelogik auf dem Server zusammenhängt. Der Kunde wird bestimmte Ereignisse vorhersagen, damit das Spiel reibungslos läuft. Aber am Ende hat der Server immer Recht.

Vorausgesagte Ereignisse sind beispielsweise das Anhalten der Bewegung, wenn eine Kollision auftritt. Stendhal verwendet ein Raster, um Elemente zu positionieren. Und vom Server aus gesehen befindet sich die linke obere Ecke jeder Entität auf genau einem Quadrat. Der Kunde wird sie jedoch problemlos zwischen den Kacheln hin- und herbewegen. Es wird auch den Pseudo-3D-Effekt zeichnen. Daher kann eine Entität mit einer Basis von 1x1 im Client höher sein.

Wie können Lastprobleme ausgeglichen werden?

Versuchen Sie dies so einfach wie möglich zu halten, um die Wartung zu vereinfachen.

Der Lastenausgleich statischer Inhalte ist im Bereich der HTTP-Servercluster und Inhaltsverteilungsnetzwerke bekannt.

Ein ziemlich einfaches Konzept für den Lastenausgleich von Spieldiensten besteht darin, Server über Regionen / Zonen aufzuteilen. Die Zone AC befindet sich also auf einem Server und die Zonen DF auf einem anderen. Dies ist besonders einfach, wenn Sie nicht von Zonen in einem Satz zu Zonen in einem anderen Satz schauen können. Sie müssen dort einige Überprüfungen vornehmen, damit ein Client nur eine Verbindung zu einem Zonenserver herstellen kann, der für die Zone zuständig ist, in der sich der Player befindet.

Die einfachste Möglichkeit, Spieler von einem Server auf den anderen zu übertragen, besteht darin, sie in die Datenbank zu schreiben, den Client anzuweisen, eine Verbindung zum anderen Zonenserver herzustellen und sie vom aktuellen Server zu trennen. Der Client stellt dann eine Verbindung zum neuen Zonenserver her, der ihn aus der Datenbank lädt. (Da Sie ohnehin das Laden von / Speichern in den Datenbankcode benötigen, kann die direkte Kommunikation zwischen den Servern für die Übergabe später implementiert werden.)

Einige zusätzliche globale Dienste werden benötigt durch: Beim Anmelden müssen die Clients angewiesen werden, sich mit dem richtigen Zonenserver zu verbinden. Und vielleicht möchten Sie ein weltweites Chat-System.

Ich habe dieses Thema ausführlich unter Wie wird in MMOs ein Lastenausgleich erreicht?

Hendrik Brummermann
quelle
1
Sie haben erwähnt, dass UDP etwas mehr CPU benötigt, aber Sie haben nicht erwähnt, dass TCP mindestens drei Trips zwischen Client und Server erfordert, bevor das Paket verarbeitet wird, UND die Pakete werden gepuffert, bis alle vorherigen Pakete empfangen wurden, was möglicherweise lächerlich ist Wartezeiten auf Pakete, die nicht mehr relevant sind. Scheint wichtig zu sein.
BlueRaja - Danny Pflughoeft
2
@Danny, Es sind drei Pakete erforderlich, um eine neue TCP-Verbindung herzustellen: Client zum Server: SYN, Server zum Client: SYN ACK, Client zum Server: ACK + Daten. Dies ist ein Roundtrip mehr als UDP. Dies geschieht jedoch erst zu Beginn, wenn der Client zum ersten Mal eine Verbindung zum Server herstellt. Bei einer eingerichteten Verbindung wird jedes Paket sofort ohne zusätzliche Roundtrips verarbeitet. Es erfolgt eine ACK-Antwort, aber die empfangenen Daten werden bereits verarbeitet, während die ACK-Pakete zurücklaufen.
Hendrik Brummermann
1
@Danny, TCP behandelt Paketverluste automatisch und auf sehr effiziente Weise. Es ist schwer, sich mit UDP neu zu implementieren. es sei denn, Ihr Protokoll ist in Ordnung mit zufälligen nicht zugestellten Paketen. Das nächste Problem ist, dass TCP die Reihenfolge der Pakete sicherstellt, während UDP-Pakete möglicherweise in der falschen Reihenfolge empfangen werden. Auch hier ist es schwierig, dies selbst erneut zu implementieren, es sei denn, Sie können ältere Pakete, beispielsweise basierend auf einem Paketzähler, einfach ignorieren. Wenn für TCP eine sehr kurze Antwortzeit erforderlich ist, muss der Nagle-Algorithmus deaktiviert werden.
Hendrik Brummermann
Anscheinend haben Sie Ihre Position vehement verteidigt, ohne das eigentliche Problem der TCP-Verzögerung zu lösen. Vielleicht ist das wahre Problem Ihre Wahl einer Hardware-Firewall anstelle eines DDoS-resistenten Protokolls
MickLH
27

http://gafferongames.com/networking-for-game-programmers/

Ist eine großartige Sammlung von Artikeln zu verschiedenen Problemen und Lösungen, die sich mit dem Networking von Spielen befassen.

jsimmons
quelle
1
+1, aber bitte vertraue ihnen nicht blind. Nach meiner Erfahrung ist es beispielsweise keine gute Idee, UDP zu verwenden und die Funktion von TCP neu zu erfinden. UPD ist nur dann sinnvoll, wenn verlorene Pakete überhaupt keine Auswirkung haben, dh jedes UDP-Paket den gesamten relevanten Stand der Welt enthält. WoW verwendet TCP, SL wird gerade von UDP auf TCP umgestellt (sogar HTTP für statische Inhalte) und hat mit diesen Änderungen die Leistung erheblich verbessert.
Hendrik Brummermann
7
Sie erfinden die TCP-Funktionen jedoch nicht neu, zumindest nicht alle. Die Semantik der TCP-Flusskontrolle und des Paketverlusts ist für ein Spiel, das eine Verbindung mit geringer Latenz erfordert, schrecklich. TCP ist nur dann nützlich, wenn Sie sich nicht um Latenz oder die Minimierung der erforderlichen Bandbreite kümmern.
Jsimmons
2
Second Life verbesserte die Leistung massiv, indem es von UDP zu HTTP über TCP wechselte: blogs.secondlife.com/community/technology/blog/2010/08/13/…
Hendrik Brummermann
5
Äh, nicht wirklich, sie haben die Leistung ihres Asset-Streamings verbessert, indem sie die Funktionsweise geändert haben. Die Verwendung von HTTP / TCP in dieser Instanz erleichterte deren Implementierung und beschleunigte sie nicht. Ich könnte auch bemerken, dass zeromq ein interessantes Projekt ist und sich sehr gut für die Vernetzung von Spielen eignet. zeromq.org
jsimmons
8

Abhängig von der Art des Spiels, das Sie schreiben, können Sie möglicherweise einen Teil der Netzwerkprogrammierung auf niedriger Ebene vermeiden. Einige Arten von Spielen erfordern nicht viel Hin- und Her-Kommunikation zwischen den Clients und dem Server. In solchen Fällen könnte man sich für ein übergeordnetes Framework entscheiden. Zum Beispiel entwickle ich ein rundenbasiertes Strategiespiel in C # /. NET. Rundenbasierte Strategiespiele sind insofern einzigartig, als der Großteil der Client / Server-Kommunikation zu Beginn und am Ende einer Runde stattfindet, wobei relativ wenig dazwischen liegt. Daher entschied ich mich für die Windows Communication Foundation (WCF), ein allgemeines Kommunikationsframework, das hauptsächlich für Webdienste entwickelt wurde. Anstatt direkt mit Sockets und all dem Low-Level-Netzwerk-Gunk zu arbeiten, kann ich so etwas wie Standardmethodenaufrufe machen. und überlasse WCF mir die Protokoll- und Transportschicht. Das einzige Mal, dass ich mich mit dem Netzwerk auf niedriger Ebene befassen musste, war, als ich meine Endpunkte konfiguriert habe. Dies ist so ziemlich ein einmaliger Vorgang in einer Konfigurationsdatei. Möglicherweise muss noch eine benutzerdefinierte Serialisierungslogik implementiert werden, aber Sie müssen dies trotzdem tun.

Mike Strobel
quelle
8

Die Frage ist viel zu weit gefasst. Die Antworten könnten eine Website alleine füllen. Aber es gibt Bücher, die dies berühren, hauptsächlich diese beiden:

Beachten Sie, dass auch diese Bücher keine vollständige Anleitung sind, sondern eine Sammlung von Ideen und Ansätzen, die Sie verwenden können, von denen einige nicht zusammenarbeiten oder die sogar widersprüchlich sind. In der Regel setzt es einige Erfahrung in der Entwicklung von Spielen, Netzwerkanwendungen oder im Idealfall beidem voraus.

(Beachten Sie, dass ich in der ursprünglichen Frage mehr über die MMOs spreche - ein 'Netzwerkspiel' kann alle möglichen Dinge von einem PHP-basierten Textspiel bis hin zu einem MMO bedeuten, und die obigen Unterfragen sind es nicht alle gelten für jeden Typ.)

Kylotan
quelle
7

Wie können Lastprobleme ausgeglichen werden?

feste geografische Größe + mehrere Instanzen ist die einfachste Lösung. Die Leute, die an SWG arbeiteten, versuchten es mit dynamischer Größe und bedauerten es.

Wie verwalte ich den Spielstatus?

Der Server ist maßgebend.

Wie halte ich die Dinge synchron?

Regelmäßige Synchronisierungsaktualisierungen vom Server. (nicht ganz sicher, was die Sorge hier ist)

Wie schützt man die Kommunikation und den Client vor Reverse Engineering?

Unmöglich. Stellen Sie einfach sicher, dass Sie nichts vertrauen, was Sie vom Client erhalten, und dass der Server autorisierend ist.

Wie kann man Latenzprobleme umgehen?

Dies geht kilometerweit, aber oberflächlich gesehen führen Sie auf dem Client dieselbe Simulation aus wie auf dem Server. Wenn die Synchronisierung stattfindet, können Sie die Probleme beheben. Alle Entscheidungen, die auf dem Client getroffen werden, werden auch auf dem Server simuliert. Es kann also zu Fehlentscheidungen kommen, aber die Dinge klappen im Allgemeinen.

Welche Dinge sollen lokal berechnet werden und welche Dinge auf dem Server?

Stellen Sie sich den Client als eine nicht autorisierende Simulation dessen vor, was auf dem Server vor sich geht. Reaktionsfreudigkeit ist der Schlüssel für das Spielerlebnis. Sie müssen also jedes Mal etwas unternehmen , wenn ein Spieler eine Entscheidung trifft, auch wenn es sich nur um den Beginn eines Taktes handelt.

Um ehrlich zu sein, viele dieser Probleme sind orthogonal und können später gelöst werden. Mach einfach das Spiel und sorge dich nicht zu sehr um diese Dinge.

Aaron Brady
quelle
4

Diese Frage ist sehr weit gefasst. Es ist auch ein sehr kniffliger Bereich, den man meistern muss. Netzwerk-Programmierer sind in der Branche sehr gefragt, mit einer entsprechenden Bezahlung. Gibt es da draußen Bücher? Gibt es da draußen ohne Zweifel gute Bücher? Gibt es da draußen Bücher, die deine Fragen beantworten? Ich glaube nicht. Sie haben vielleicht Lösungen, die in bestimmten Situationen funktionieren, oder Hinweise darauf, wonach Sie suchen müssen, aber fast alle Ihre Fragen sind spielabhängig. In diesem Bereich müssen Sie wirklich viel allein arbeiten trivial und es kann auf so viele (unkontrollierte) Arten schief gehen.

Kaj
quelle