Wie würden Sie einen rundenbasierten Spieleserver als RESTful-API modellieren? Zum Beispiel einen Schachserver, auf dem Sie Schach gegen einen anderen Kunden derselben API spielen können. Du brauchst eine Möglichkeit, um ein Spiel mit dem anderen Kunden anzufordern und zu verhandeln, und eine Art, die einzelnen Spielzüge zu spielen.
Ist dies ein guter Kandidat für eine REST (RESTful) API? Oder sollte das anders modelliert werden?
Welche Ressourcen möchten Sie modellieren? Ich würde vier haben: Sie, Ihr Gegner, das bestimmte Spiel (Sitzung, Instanz) und das Spielbrett. Also würde es mit etwas wie
anfangen %Vor%Wir haben ein gutes Intro / einen Überblick über InfoQ .
Ich denke so etwas wie:
%Vor%soweit die grundlegenden Ressourcen betroffen sind. Ich bin mir nicht sicher, wie ich mit dem "Hat der andere Spieler schon umgezogen?" Umgehen konnte. Idee, obwohl. Ich habe darüber nachgedacht, den GET-Anforderungsblock einfach zu halten, bis der Zug gespielt wird - d.h. Mein Klient würde die Koordinaten meines Zuges auf
setzen %Vor%und dann würde GET
%Vor%Der Server antwortet nicht sofort, sondern hält die Verbindung offen, bis der andere Spieler sich bewegt hat (d. h. PUT an diesen Ort). Ist das was Nakajima als "kometös" bezeichnet?
Charlie, ich bin mir nicht ganz sicher, was Sie mit dem "Token" gemeint haben, an wessen Seite es steht - löst das dasselbe Problem ohne die Notwendigkeit eines Pollings oder einer blockierenden Verbindung?
Ist es für Player-IDs sinnvoll, diese als Ressource in einem Teil der URL zu modellieren? Ich plante, einfach die HTTP-Benutzerauthentifizierung zu verwenden (wobei der Benutzer / Ausweis als Teil jeder Anfrage gesendet wird). Sie könnten immer noch die meisten Ressourcen ohne Authentifizierung abrufen, aber wenn Sie versucht haben, sagen Sie,
%Vor%es würde Ihnen einen Fehler mit der Berechtigung verweigert geben, wenn Sie nicht die richtigen Zugangsdaten für dieses Spiel hätten.
OK, die Grundidee von REST besteht darin, dass Sie den Status übertragen; Sie möchten wenig oder keinen "Sitzungsstatus" auf dem Server haben. Sie möchten also nicht den Sitzungszustand und Keepalive verwenden, was Comet tut. Aber denken Sie an das Beispiel eines Spiels per Post: Sie haben beide eine Kopie des Spielplans und Sie tauschen Züge aus. Die Post weiß nichts über das Spiel.
Nun, ich gebe zu, dass dies in meinen Gedanken wächst, wenn ich darüber nachdenke - in der Tat, ich könnte einen Artikel basierend auf dieser Frage schreiben - aber hier ist die Idee, wie einige Geschichten:
Sie brauchen nicht viel in Bezug auf den Server-Status --- obwohl Sie dies vielleicht erweitern möchten, indem Sie Bewegungen usw. verfolgen, sagen Sie für das Ranking - und die Frage, wer das Recht hat, sich zu bewegen, kann berechnet werden ganz von der Board-Seite: Wenn Sie das Recht haben, haben Sie ein Formular für die Eingabe eines Zuges; Wenn Sie die Rückgabe des Formulars zurücksenden, gibt die Antwort eine Seite ohne Slot für die Eingabe eines Zuges zurück.
Mit dem "Token" meine ich nur eine willkürliche Darstellung dieses einen Zustands des Zustands "My move" / "your move".
Scheint, als ob die benötigten Ressourcen
sindDanke, Charlie. Mir ist immer noch nicht klar, wie Sie über die Bewegung des Gegners in Ihrem Plan informiert werden. Natürlich kann die Frage, wer das Recht hat, sich zu bewegen, einfach berechnet werden - entweder von der Board-Ressource oder durch Verwendung einer separaten Ressource, die explizit angibt, an wen sie sich wenden soll. Aber wie weiß ein Kunde, dass sich diese Ressource geändert hat? Muss es einfach ständig abfragen und sich an den vorherigen Zustand erinnern, bis es bemerkt, dass sich etwas geändert hat? Im Post Office-Modell "pusht" die Post eine Nachricht an den Client (Ihr Postfach), was in HTTP nicht möglich ist.
Ich nehme an, dies ist Teil einer allgemeineren Frage: Wenn es eine REST-Ressource gibt, die ich auf Änderungen oder Modifikationen überwachen möchte, was ist der beste Weg, dies zu tun? Und gibt es etwas, was der Server tun kann, um dies für den Kunden einfacher zu machen?
Ich denke, ich werde das als eine separate Frage veröffentlichen, da ich denke, dass es von selbst interessant ist.
Bearbeitet, um hinzuzufügen: Was? ist eine REST-konforme Möglichkeit, eine REST-Ressource auf Änderungen zu überwachen?
Ich denke nicht, dass REST eine gute Wahl für solch eine Anwendung ist. Die Transformationen und Operationen, die Sie ausführen müssen (verschieben, Verlauf anzeigen, rückgängig machen, Vorschlag abrufen, Benachrichtigung ändern), werden nicht gut auf das Ressourcenkonzept von REST abgebildet. (Die Schwierigkeiten sind vielleicht noch offensichtlicher, wenn man bedenkt, wie eine REST-API für kompliziertere Turn-basierte Spiele wie Scrabble oder Monopoly aussehen könnte.)
Ich denke, jede vernünftige REST-API würde wahrscheinlich ein Wrapper um etwas sein, das nicht REST-konform ist, wie etwa ein statusfähiges Protokoll, das portable gesendet hat Spielnotation hin und her.
Ich denke, Sie könnten es RESTvoll modellieren . Implementierung wird schwieriger, weil Sie entweder einen Kometen benötigen) -esque Lösung oder Sie müssten den Server in einem relativ kurzen Intervall über AJAX abfragen.
Im Hinblick darauf, wie Sie eine REST-konforme Oberfläche bereitstellen würden, würde ich sagen, dass Sie ein Spielbrett mit Koordinaten, Teilen, die diese Koordinaten belegen können, und Aktionen, die diese Koordinaten ändern, benötigen.
Wenn ein Spieler einen Zug macht, wird eine neue Aktion erstellt. Nach der Überprüfung, um sicherzustellen, dass es zulässig ist, aktualisieren Sie den Status des Spiels und rendern dann die Antwort, die zum Aktualisieren der Benutzeroberfläche erforderlich ist.
Im Grunde genommen würde ich das so modellieren. Die Implementierungsseite ist jedoch, was ich hier als größere Schwierigkeit ansehe.
Du beginnst damit, zum Spiel zu gehen und nach einem Partner zu suchen, also
%Vor%gibt Ihnen eine Liste der Wartenden. Wenn du kommst, wenn niemand wartet, bekommst du eine Spiel-ID; Andernfalls wählst du jemanden aus, der wartet und erhalte die Spiel-ID, die sie haben.
%Vor%zeigt dir das Board. Du brauchst etwas, um die Entscheidung zu treffen, wer weiß spielt, ich überlasse das als Übung. Die GET-Operation gibt Ihnen das Board, also sendet ein POST einen Zug; Wenn Sie die Bewegung nicht haben, erhalten Sie einen Fehler. Sie finden das Ergebnis beim nächsten GET.
Hölle, in diesem Modell benutze ich nicht einmal die Spieler-ID, obwohl es gut sein könnte, damit niemand sich als Kibitzer ins Spiel schleichen kann.
Ihr Gedanke ist also, dass, anstatt die Aktionen zu einem erstklassigen Objekt zu machen, jede Bewegung als eine Aktualisierung des Spiels selbst betrachtet wird? Es ist sicherlich eine andere Art, es zu tun, obwohl ich denke, dass ich das Action-Objekt aus mehreren Gründen lieber in seine eigene First-Class-Entity aufteilen würde. Der größte Grund ist, dass ich glaube, dass es überprüfbar ist. Ob eine Bewegung gültig ist oder nicht, könnte im Aktionsobjekt liegen, anstatt sich darum zu sorgen, dass die Karte jederzeit in einem gültigen Zustand ist. Zugegeben, ich weiß nicht, was beide Ansätze mit sich bringen würden, aber das fühlt sich für mich besser an.
Der andere Grund, den Sie völlig über YAGNI widerlegen können, ist, dass ein Action-Objekt erster Klasse eine Geschichte von Zügen bereitstellen würde. Interessant vielleicht, aber wenn eine Anforderung, ist ein strittiger Punkt.
Einer der Entwickler in planet.jabber ist an Chesspark , eine Online-Schach-Community. Sie verwenden Jabber / XMPP ausgiebig; Wenn ich mich nicht irre, sind dies seine Beiträge zum Thema .
XMPP ist ein Instant-Messaging-Protokoll, das grob auf einem kleinen XML-Nachrichtenaustausch basiert. Es gibt Bibliotheken für die meisten Sprachen, einschließlich Javascript. Ich bin mir nicht sicher, ob es zu deinem Problem passt.
Bei einem einfachen Spiel wie Schach geht es eigentlich nur darum, den Medientyp zu definieren.
Hier ist ein Beispiel für einen wahrscheinlich vereinfachten Mediatyp, um ein Schachspiel zu modellieren.
Ich überspringe die Verwaltung mehrerer Spiele, die möglicherweise auf demselben Server laufen, und modelliere ein bereits laufendes Spiel.
Der erste Schritt besteht normalerweise darin, einen Index für die Anwendung zu definieren.
index
Der Einstiegspunkt für das Spiel. Holen Sie dies, um Informationen über das Spiel zu entdecken.
Die Payload könnte etwa so aussehen:
%Vor% move
Senden Sie eine JSON-Payload an Links, die mit einem rel
von move
gekennzeichnet sind, um ein Stück zu verschieben. Die folgenden Felder müssen enthalten sein:
Erfolgreiche Antworten haben einen Statuscode von 200 und enthalten eine Entität, die genauso wie die index
Nutzlast mit dem aktualisierten Status des Spiels ist.
400, wenn der Benutzer sein Stück dort nicht bewegen darf oder wenn er nicht an der Reihe ist.
player
ERHALTE eine Beschreibung eines Spielers.
Die folgenden Felder MÜSSEN in der Antwort enthalten sein:
piece
Pieces sind in die index
-Nutzlast eingebettet, können aber selbst existieren. Jedes piece
MUSS die folgenden Felder haben:
Jedes Stück muss einen move
link haben.
Eine alternative Designentscheidung, die ich hier hätte treffen können, war, für jeden gültigen Zug eine individuelle Verbindung bereitzustellen. Es mag gute Gründe dafür geben, aber ich wollte zeigen, dass es nicht erforderlich ist. Es gibt wahrscheinlich eine Handvoll anderer Ressourcen, die Sie verwenden möchten, um Dinge zu behandeln, die dem Kunden helfen, festzustellen, wer an der Reihe ist und was nicht.
Für kompliziertere Spiele, wie Civilization, RTSs, FPSs oder MMOGs und was nicht, ist das vielleicht nicht so praktisch IMO.