Dokumentation Cluedo-Protokoll Protokoll Version 1.3 Sebastian Bschorer ∗ 27. Juli 2015 Änderungen gegenüber früheren Versionen Neu in Version 1.3 • Die "poolcards"-Nachricht unter 9.3 muss selbstverständlich die GameId beinhalten. • Nach einem erfolgreichen Login 5.2 können die "person positions" und "weapon positions" in den Spielinfos noch fehlen. Hinweis: Aufgrund der nahen Abgabetermine ist der Testserver weiterhin mit Versionsnummer 1.2.1 kompatibel, die jedoch intern schon mit 1.3 arbeitet.) Neu in Version 1.2.1 • Die "game started"-Nachricht unter 8.5 wird an alle verbundenen Clients gesendet und nicht nur an die Spielteilnehmer. • Selbiges gilt auch für die "game ended"-Nachricht unter 8.6. Hinweis: Bei dieser Protokolländerungen müssen keine JSON-Nachrichten umgebaut werden. Lediglich die Versionsnummer muss geändert werden. Daher auch die Art der Versionsnummerierung. Das soll vor allem sicherstellen, dass die Protokolländerung wahrgenommen wurde.) Neu in Version 1.2 • Der Spielerzustand in 6.7 wird als Array übergeben. In diesem Array sind alle aktuellen Spielzüge enthalten, die der Spieler machen darf. Ein Statusupdate sollte immer an alle Spielteilnehmer versendet werden. • "nick" und "playerstate" in stateupdate (9.1) wurden entfernt und durch ein "player"Objekt ersetzt. • Der Testserver wurde bereitgestellt (vgl. 4). ∗ Basierend auf dem Catan-Protokoll von Erich Schubert und Johannes Lohrer, WiSe 14/15 1 Neu in Version 1.1 • Nachrichten für den UDP-Handshake spezifiziert (vgl. 5.1). • Würfelwurf unter 9.2 als Array von zwei Würfeln festgelegt. • In der Spielerinfo wird die Kartenanzahl und die Spielfeldposition nicht mehr übergeben. • Stattdessen gibt es eine neue Version der Spielinfo (vgl. 6.6). • Tritt ein Zuschauer einem Spiel bei, erhält er eine Spielinfo-Nachricht (vgl. 8.3). • Der Aufbau einer "moved"-Nachricht wurde umgeschrieben. (vgl. 9.3) • Der Typ von "jsonID" unter 7.1 wurde als positive Ganzzahl spezifiziert. • Ein Client kann in demselben Spiel nicht Spieler und Zuschauer gleichzeitig sein. • Es wurde festgelegt, dass der Server ein Spiel beendet, falls ein Spieler das Spiel vorzeitig verlässt. 2 1 Grundlagen Die Daten werden über einen persistenten TCP-Stream übertragen. Der Port ist dabei nicht festgelegt. Das Protokoll verwendet einen Strom von JSON-Objekten, als Zeichensatz wird dabei UTF-8 verwendet. Objekte müssen dabei so kodiert werden, dass sie selbst keine Zeilenwechsel enthalten (optionale Zeilenwechsel müssen weggelassen werden, in Zeichenketten verwenden Sie "\n"). Ein Zeilenwechsel darf ausschließlich als Trennsymbol für Objekte verwendet werden (gestalten Sie aber ihren Parser hierfür möglichst tolerant, damit er auch mit fehlerhaften Nachrichten umgehen kann). Nach jedem Objekt müssen Sie einen Zeilenwechsel schicken. Unterschiedliche Nachrichtentypen sind durch sogenannte Wrapper-Objekte modelliert. Ein Objekt darf dabei stets nur eine Nachricht enthalten. Die allgemeine Form einer Nachricht sieht folgendermaßen aus: { "type" : String, "Attribut" : "Wert", "2. Attribut" : "Wert" } Statt einem primitiven "Wert" können hier jedoch auch komplexere JSON-Objekte auftreten. Zeilenwechsel müssen bei der Serialisierung weggelassen oder kodiert werden, so dass die Nachricht dann beispielsweise wie folgt verschickt wird: {"type":String, "Attribut":"Wert","2. Attribut":"Wert"} 2 Kompatibilität Ihre Implementierung braucht nur die neueste Protokollversion unterstützen. Momentan handelt es sich dabei um Version "1.3". Ihr Client soll mit jedem Server funktionieren, der dieses Protokoll korrekt implementiert. Ebenso soll ihr Server (zumindest im Kompatibilitätsmodus) mit jedem Client spielbar sein. Insbesondere gilt dies für die KI-Spieler. Eigene Erweiterungen können Sie gerne vornehmen, allerdings muss ihr Client und Server über einen Kompatibilitätsmodus verfügen, der Interoperabilität gewährleistet. 3 3 Hinweise zu JSON • Verlassen Sie sich nicht darauf, dass ein einzelner read() Aufruf die vollständige Nachricht liefert. Das Betriebssystem kann die Nachrichten fragmentiert übertragen. Füllen Sie einen Puffer so lange, bis die empfangene Nachricht ein vollständiges JSON-Objekt ergibt (ein korrekter Server sollte anschließend auch einen Zeilenwechsel senden). • Die Verwendung von Bibliotheken wie JSON.org, Jackson, GSON, etc. hierfür ist sinnvoll. Keinesfalls sollte das Protokoll manuell per print erzeugt werden. • Beachten Sie die UTF-8 Kodierung von Umlauten. Empfehlenswert ist es, Ihr gesamtes Projekt in Eclipse als UTF-8 zu konfigurieren, um Probleme mit Windows zu vermeiden (OSX und Linux verwenden normalerweise bereits UTF-8). 4 Testserver Im CIP-Pool ist ab sofort ein Testserver verfügbar mit dem Sie ihre Implementierung testen können. Innerhalb des MWN-Netzes1 ist es möglich, über den Port 30305 eine Verbindung zum Server mit der Adresse vanuabalavu.pms.ifi.lmu.de aufzunehmen. Um schnelleres Testen zu ermöglichen, kann ein Spiel schon gestartet werden, wenn nur ein Spieler dem Spiel beigetreten ist. Da nicht auszuschließen ist, dass der Server fehlerfrei läuft, teilen Sie bitte frühzeitig mit, wenn Sie ein Fehlverhalten vermuten. Ist der Server nicht verfügbar, so probieren Sie es bitte später nochmals. Gerne an mich per Mail an [email protected]. 1 Sie können auch von zu Hause aus eine Verbindung zum Testserver aufbauen, wenn Sie im Vorfeld eine VPN-Verbindung in das MWN-Netz herstellen. Informationen dazu finden Sie unter https://www.lrz.de/services/netz/mobil/ vpn/anyconnect/. 4 5 Verbindungsaufbau 5.1 UDP-Handshake Um das Verbinden zu einem Server im lokalen Netz zu vereinfachen, soll es möglich sein, einen UDPHandshake durchzuführen. Server und Client kommunizieren dabei über den Port 30303. Dieser ist laut IANA nicht zugewiesen und daher frei. Wenn ein UDP-Server gestartet wird, soll er sich mit folgender Nachricht über Broadcasts im Netzwerk bemerkbar machen: {"type":"udp server","group":String,"tcp port":int} Bei "group" handelt es sich dabei um den Gruppennamen. Laufende Clients können diese Nachricht über UDP empfangen und erhalten dadurch den "tcp port" für die TCP-Verbindung zum Server. (Dieser muss sich vom UDP-Port unterscheiden!) Die dazugehörige IP kann der Client aus dem eingehenden Datenpaket auslesen. Wird ein Client gestartet, kann er mittels folgender Nachricht nach Servern im lokalen Netz suchen: {"type":"udp client","group":String} Ein Server, der diese Nachricht empfängt, antwortet mit der bereits oben spezifizierten Nachricht. Mit der IP-Adresse und dem TCP-Port kann ein Client anschließend eine TCP-Verbindung zum Server aufbauen. Sind mehrere Server im lokalen Netz verfügbar, so kann der Client auswählen, zu welchem er sich verbinden möchte. Achtung: Die UDP-Broadcasts funktioniert nur im lokalen Netz. Ein Client sollte daher auch die Möglichkeit haben, IP-Adresse des Servers sowie den Port manuell einzugeben. 5.2 Login am Server Steht die TCP-Verbindung, so ist der Client zunächst noch nicht angemeldet. Der Server reagiert in diesem Zustand nur auf die Nachricht "login" und sendet selbst keinerlei Nachrichten an diesen Client. Eine "login" ist nach folgendem Schema aufgebaut: { "type" : "login", "nick" : String, "group" : String, "version" : "4.2", "expansions" : [ String ] } "nick" repräsentiert den Benutzername. Er darf jedes beliebige UTF-8-Zeichen enthalten, muss jedoch mindestens drei Zeichen lang sein. Bei "group" wird der Gruppenname erwartet. Bei "version" handelt es sich um die Protokollversionsnummer und wird als String repräsentiert. "expansions" enthält ein Array aller Erweiterungen, die der Client beherrscht. Werden keine Erweiterungen unterstützt, so kann dieser Eintrag in der Nachricht fehlen. 5 Beispielhaft könnte eine login-Nachricht so aussehen: { "type" : "login", "nick" : "Sepp", "group" : "TestendeTentakel", "version" : "1.2.1", "expansions" : [ "Chat", "HyperHyperFeature" ] } War der Login erfolgreich, so antwortet der Server diesem Client mit einer "login successful"Nachricht. { "type" : "login successful", "expansions" : [ String ], "nick array" : [ String ], "game array" : [ SpielInfo ] } Die Nachricht enthält als "expansions" die maximale Teilmenge der Fähigkeiten enthält, die sowohl Client als auch Server haben. In der Basisversion des Protokolls müssen sowohl Client als auch Server mindestens eine Chat-Fähigkeit haben, welche mit dem Namen "Chat" bezeichnet wird (vgl. 7.2). Die Nachricht besitzt ein String-Array, welches die Nutzernamen aller angemeldeten Clients enthält. Außerdem wird ein Array aus Spielinfos mit dieser Nachricht übertragen. Dieses Array soll alle momentan verfügbare Spiele des Servers enthalten. Der Aufbau einer Spielinfo ist unter 6.6 erklärt. Die Attribute "person positions" und "weapon positions" dürfen hierbei noch fehlen. Alle anderen angemeldeten Clients erhalten vom Server eine Nachricht der Form: {"type":"user added","nick":String} Wird ein Client beendet, sollte er sich beim Server abmelden mittels: {"type":"disconnect"} Bevor die Socket-Verbindung abgebrochen wird, reagiert der Server mit einem abschließenden: {"type":"disconnected","message":String} Alle anderen Clients werden darüber informiert: {"type":"user left","nick":String} Sollte es laufende Spiele geben, denen dieser Client beigetreten war, so beendet der Server das Spiel und schickt an alle Clients eine "game ended"-Nachricht (vgl. 8.6). 6 6 Objekte Nachrichten können verschiedene Objekte enthalten. Diese werden als JSON-Objekte übertragen. 6.1 Spielfeld Das Spielfeld ist folgendermaßen definiert und besitzt (mit Ausnahme des Schwimmbads) den gleichen Aufbau wie die älteren Brettspielversionen: y-Achse x-Achse 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 Eingangshalle Arbeitszimmer Salon S W S S S Bibliothek N O N O S Schwimmbad N W Billardzimmer W Speisezimmer S O N N N O Wintergarten W O Musikzimmer Küche 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 7 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 6.2 Felder Jedes Quadrat repräsentiert ein begehbares Feld und wird als ein Objekt mit einer "x"- und einer "y"-Koordinate repräsentiert: {"x" : 15, "y" : 16} Folgende Feldertypen sind definiert: • Auf hellen Feldern können sich die Spielfiguren bewegen. Auf jedem dieser Felder darf sich maximal eine Spielfigur gleichzeitig befinden. • Die sechs farbigen Felder bestimmen die Startpositionen der einzelnen Farben. Rot zum Beispiel besitzt die Startposition (16, 0). Abgesehen davon handelt es sich bei Ihnen um reguläre Spielfelder. • Die Felder mit dem Buchstaben darin symbolisieren eine Tür in einen Raum. Die vier Buchstaben N, O, S, W bestimmen die Himmelsausrichtung der Tür. Auf diesen Feldern dürfen sich beliebig viele Spielfiguren befinden. Das Arbeitszimmer kann beispielsweise nur von Süden aus, von (6, 4) → (6, 3) betreten werden. Die Felder (7, 3) und (6, 3) sind nicht benachbart. Landet eine Spielfigur auf einer Tür, so hat sie den Raum betreten. Räume an sich sind keine begehbaren Spielfelder, begrenzen aber durch ihre Anwesenheit das Spielfeld. Ein Raum ist definiert durch die Menge der Türen, die in diesen Raum führen. Der Spielfeldaufbau (samt Startpositionen) ist statisch und muss daher nicht über das Netzwerk kommuniziert werden. 6.3 Farben Es werden im Grundspiel sechs verschieden Farben unterstützt. In Nachrichten mit dem Attribut "color" darf die Farbe eine der folgenden Werte annehmen: "red", "yellow", "white", "green", "blue" oder "purple". 6.4 Karten Es wird zwischen drei Kartentypen unterschieden: person, weapon und room. Im Grundspiel dürfen folgende Werte angenommen werden: Personen: "red" "yellow" "white" "green" "blue" "purple" Fräulein Gloria Oberst von Gatow Frau Weiß Reverend Grün Baronin von Porz Professor Bloom 8 Waffen: "dagger" "candlestick" "revolver" "rope" "pipe" "spanner" Dolch Leuchter Revolver Seil Heizungsrohr Rohrzange Räume: "hall" "lounge" "diningroom" "kitchen" "ballroom" "conservatory" "billiard" "library" "study" "pool" Eingangshalle Salon Speisezimmer Küche Musikzimmer Wintergarten Billardzimmer Bibliothek Arbeitszimmer Schwimmbad Wird, wie unter 6.7 ein Array von Karten verlangt, so kann eine Karte entweder eine Person, eine Waffe oder ein Raum sein. 6.5 Aussagen Aussagen, wie sie bei Verdächtigungen und Anklagen verwendet werden, haben folgende Form: { "person" : Person, "weapon" : Waffe, "room" : Raum } Das Schwimmbad oder "pool" spielt eine Sonderrolle. In diesem Raum kann kein Mord stattfinden. Daher darf er auch nicht in einer Aussage auftauchen. 6.6 Spielinfo Eine Spielinfo soll den aktuellen Zustand über ein Spiel enthalten. Sie hat folgenden Aufbau: { "gameID" : int, "gamestate" : Spielzustand, "players" : [ Spielerinfo ], "watchers" : [ String ], "person positions" : [ Personenposition ] "weapon positions" : [ Waffenposition ] } 9 Spielzustand Der Spielzustand darf einen der Werte "not started", "started" oder "ended" annehmen. watchers enthält ein Array aus Nicknames derjeniger Clients, die diesem Spiel zuschauen. 6.7 Spielerinfo Die Informationen über einen Spieler sehen folgendermaßen aus: { "nick" : String, "color" : Farbe, "playerstate" : [Spielerzustand] } Wenn das Spiel noch nicht gestartet wurde, kann das Attribut "playerstate" auch fehlen oder null sein. Spielerzustand Der Spielerzustand gibt Aufschluss darüber, welche Aktionen der Server von einem Spieler als nächstes erwartet. Hat ein Spieler mehrere Möglichkeiten, so werden alle Möglichkeiten übergeben. Folgende Statusmeldungen sind spezifiziert: "do nothing" "roll dice" "use secret passage" "move" "suspect" "accuse" "disprove" "end turn" Der Spieler muss warten. Der Spieler darf würfeln. Der Spieler darf den Geheimgang benutzen. Der Spieler muss seine Figur bewegen. Der Spieler darf eine Verdächtigung äußern. Der Spieler darf anklagen. Der Spieler muss auf eine Verdächtigung reagieren. (Entweder widerlegen oder mitteilen, dass er nicht widerlegen kann.) Der Spieler darf den Spielzug beenden. 6.8 Personenposition Das Unwort Personenposition beschreibt nichts anderes als das Tupel aus Person und dem Feld, auf dem sich diese Person befindet. Sie hat diesen Aufbau: { "person" : Person, "field" : Feld } 6.9 Waffenposition Analog zu oben gibt eine Waffenposition wieder, wo eine Waffe auf dem Spielfeld liegt. Wichtig ist hierbei aber, dass sich Waffen nur in Räumen (also auf Türfeldern) befinden können. { "weapon" : Waffe, "field" : Feld } 10 7 Allgemeine Nachrichten 7.1 Bestätigungen und Fehler Der Server muss jede Aktion des Clients bestätigen. Wenn eine Aktion des Spielers nicht erfolgreich durchgeführt werden konnte, so muss ein Fehler verschickt werden (Sie werden sich aber nicht darauf verlassen können, dass jeder Server die gleichen Meldungen verschickt). Hat eine Aktion weitere Nachrichten zur Folge, so sollen erst die anderen Nachrichten verschickt werden, abschließend dann eine "ok"-Nachricht: {"type":"ok"} Kommt es bei der Verarbeitung einer einkommenden Nachricht vom Client zu einem Fehlerfall, so sendet der Server eine Nachricht vom Typ "error" an diesen Client zurück: {"type":"error","message":"..."} Diese Fehlermeldung werden zum Beispiel auch versandt, wenn ein Spieler einen ungültigen Spielzug durchführen will. Sie können nicht davon ausgehen, dass alle Server dieselben Fehlernachrichten versenden. Jeder beliebigen Nachricht an den Server kann ein Attribut "jsonID" vom Typ int beigefügt werden, wobei es sich dabei um einen positiven Wert handeln muss. Der Server verwertet diese ID nicht. Wenn sie allerdings in einer ankommenden Nachricht vorhanden ist, wird sie in einer "ok"- oder "error"-Nachricht als Attribut wieder an den Client zurückgeschickt. 7.2 Chat Jeder Server muss mindestens eine Chat-Erweiterung implementieren, die den Namen "Chat" besitzt und in den ""expansions" (vgl.5) aufgeführt wird. Um eine Chat-Nachricht an die Mitspieler zu senden verwenden Sie folgende Nachricht: {"type":"chat","message":String,"timestamp":Zeitstempel} Soll eine Nachricht nicht an alle, sondern nur an ein bestimmtes Spiel gesendet werden fügen Sie ein Attribut "gameID" mit der Spielnummer hinzu. Ist eine Nachricht nur einen bestimmten User gedacht, fügen Sie ein Attribut "nick" mit dem Nickname hinzu. Schickt ein Client eine Chatnachricht, so wird diese vom Server verteilt. { "type" : "chat", "sender" : String, "message" : String, "timestamp" : Zeitstempel } Verschickt der Server eine Chatnachricht, so fehlt das Attribut "sender". Für den Zeitstempel soll die String-Repräsentation eines java.time.LocalDateTime-Objekts verwendet werden, das die Form besitzt: "2015-04-08T15:16:23.42" 11 8 Konfiguration und Spielstart 8.1 Ein Spiel erstellen Der Server soll die Möglichkeit bieten, beliebig viele Spiele parallel verwalten zu können. Um ein neues Spiel zu erstellen, schickt der Client die Nachricht: { "type" : "create game", "color" : Farbe } Der Client tritt dem Spiel dabei gleichzeitig als Spieler mit der Farbe "color" bei. Der Server sendet daraufhin an alle Clients die Nachricht { "type" : "game created", "gameID" : int, "player" : SpielerInfo } 8.2 Einem Spiel als Spieler beitreten Anschließend können Clients folgendermaßen bei diesem Spiel beitreten: { "type" : "join game", "gameID" : int, "color" : Farbe } Der Server sendet daraufhin an alle Clients: { "type" : "player added", "gameID" : int, "player" : SpielerInfo } 8.3 Einem (laufenden) Spiel als Zuschauer beitreten Man kann einem Spiel auch als Zuschauer beitreten. Allerdings nicht als Spieler und Zuschauer gleichzeitig. { "type" : "watch game", "gameID" : int } 12 Der Server sendet daraufhin an alle Clients: { "type" : "watcher added", "gameID" : int, "nick" : String } Der neu zuschauende Spieler erhält anschließend noch eine Spielinfo: { "type" : "gameinfo", "game" : Spielinfo } 8.4 Ein Spiel verlassen Zuschauer und/oder Spieler können ein Spiel verlassen mit: {"type":"leave game","gameID":int} Daraufhin sendet der Server an alle Clients: { "type" : "left game", "gameID" : int, "nick" : String } Verlässt ein Spieler ein laufendes Spiel, beendet der Server dieses und schickt an alle Clients eine "game ended"-Nachricht (vgl. 8.6). Befinden sich in einem Spiel keine Spieler mehr, so löscht der Server das Spiel und sendet an die Clients: {"type":"game deleted","gameID":int} 8.5 Ein Spiel starten Befinden sich 3-6 Spieler im Spiel und jeder hat eine andere Farbe gewählt, so kann jeder beliebige dieser Spieler das Spiel starten mit: {"type":"start game","gameID":int} Im Erfolgsfall startet der Server das Spiel. Dabei wird jedem Spieler mitgeteilt, welche Karten er erhalten hat, z.B.: { "type" : "player_cards", "gameID" : int, "cards" : [ "candlestick", "diningroom", "ballroom", "yellow", "conservatory", "purple" ] } 13 Anschließend schickt der Server an alle verbundenen Clients die Nachricht: { "type" : "game started", "gameID" : int, "gamestate" : "started", "order" : [ "Sepp", "Josephine", "Sams" ] } Wichtig dabei ist, dass die Liste "order" vom Server gemischt wurde und ab sofort die Spielerreihenfolge festlegt. Der Spieler, der den ersten Spielzug beginnt, erhält abschließend einen Statusupdate (vgl. 9.1). 8.6 Spielende Das Spiel endet, sobald ein Spieler erfolgreich Anklage erhoben hat. Der Server versendet in diesem Fall an alle Clients folgende Nachricht: { "type" : "game ended", "gameID" : int, "nick" : String, "statement" : Aussage } "nick" ist dabei der Name des Gewinners. Die Aussage enthält die Lösung des Spiels. Haben alle Spieler falsche Anklage erhoben oder endet das Spiel vorzeitig, so wird ebenfalls eine "game ended"Nachricht verschickt, allerdings fehlt in dieser dann der "nick". 14 9 Nachrichten des Servers im Spiel 9.1 Statusupdate eines Spielers Wenn sich der Zustand eines Spielers ändert (beispielsweise er am Zug ist), so sendet der Server ein Statusupdate an alle Spielbeteiligten. Diese Nachricht enthält den betreffenden Spieler und sein neuer Status. Für alle anderen Spieler gilt ab dem Moment "do nothing". { "type" : "stateupdate", "gameID" : int, "player" : SpielerInfo } Diese Nachricht soll vom Server dazu genutzt werden, den allgemeinen Spielablauf (wer ist am Zug etc.) zu steuern, insbesondere für KI-Spieler. Gültige Statusmeldungen hierfür sind im Abschnitt 6.7 spezifiziert. Insbesondere ist ein Status wie bspw. "roll dice" als Aufforderung zu sehen, den nächsten Zug zu machen. 9.2 Würfeln Hat ein Spieler gewürfelt, so sendet der Server das Ergebnis. { "type" : "dice result", "gameID" : int, "result" : [ 3, 5 ] } 9.3 Spielfigur bewegen Hat ein Spieler seine Spielfigur bewegt, so sendet der Server die neue Position der Spielfigur: { "type" : "moved", "gameID" : int, "person position" : Personenposition } Falls der Spieler das Schwimmbad betreten hat, erhält er die Nachricht: { "type" : "poolcards", "gameID" : int, "cards" : [ Karte ] } 15 9.4 Verdacht geäußert Hat ein Spieler einen Verdacht geäußert, teilt der Server diesen an alle mit: { "type" : "suspicion", "gameID" : int, "statement" : Aussage } Anschließend fragt der Server den Spieler links vom aktiven Spieler mittels Statusupdate "disprove", ob er die Verdächtigung widerlegen kann. Dieser muss daraufhin antworten (vgl. 10.5). Konnte der Verdacht widerlegt werden, antwortet der Server mit dieser Nachricht: { "type" : "gameID" "nick" : "card" : "disproved", : int, String, Karte } "nick" ist in diesem Fall derjenige Spieler, der den Verdacht widerlegen konnte. Wichtig: Nur derjenige, der die Verdächtigung geäußert hat, bekommt diese Karte zu sehen. Bei den übrigen Spielern fehlt das Attribut "card". Konnte der gefragte Spieler den Verdacht nicht widerlegen, frägt der Server reihum den nächsten. Falls niemand den Verdacht widerlegen konnte, sendet der Server eine Nachricht im Format: { "type" : "no disprove", "gameID" : int } Abschließend erhält der aktive Spieler einen entsprechenden Spielerzustand. 9.5 Anklage erhoben Hat ein Spieler Anklage erhoben und lag dabei richtig, so endet das Spiel und der Server schickt die Nachricht "game ended" an alle Spieler (vgl. 8.6). War die Anklage falsch, so scheidet der Spieler als aktiver Spieler aus. Der Server sendet daraufhin diese Nachricht an alle Spieler: { "type" : "wrong accusation", "gameID" : int, "statement" : Aussage } 16 10 Nachrichten eines Spielers im Spiel 10.1 Würfeln Um zu Würfeln, sendet der Spieler folgende Nachricht: { "type" : "roll dice", "gameID" : int } 10.2 Spielfigur bewegen Um die eigene Spielfigur zu bewegen, wird an den Server folgende Nachricht geschickt: { "type" : "move", "gameID" : int, "field" : Feld } 10.3 Geheimgang nutzen Um den Geheimgang zu nutzen um in gegenüberliegende Räume zu gelangen, sendet der Spieler folgende Nachricht: { "type" : "secret passage", "gameID" : int } 10.4 Verdächtigung äußern Äußert der Spieler eine Verdächtigung, so hat eine entsprechende Nachricht an den Server diese Form: { "type" : "suspect", "gameID" : int, "statement" : Aussage } Da der Raum implizit durch die Position des Spielers abgeleitet werden kann, kann das Attribut "room" in diesem Statement fehlen. (Nach Regel darf ein Verdacht nur in dem Raum ausgesprochen werden, in welchem sich die eigene Spielfigur befindet). 17 10.5 Auf eine Verdächtigung reagieren Wird man aufgefordert eine Verdächtigung zu widerlegen und kann sie auch widerlegen, so muss man dies auch. Eine Nachricht hat dann diese Form: { "type" : "disprove", "gameID" : int, "card" : Karte } Kann eine Verdächtigung nicht widerlegt werden, so fehlt das Attribut "card". 10.6 Spielzug beenden Der Spielzug kann beendet werden mit der Nachricht: {"type":"end turn","gameID":int} 10.7 Anklagen Eine Anklage wird folgendermaßen codiert: { "type" : "accuse", "gameID" : int, "statement" : Aussage } Anklagen sind an keinen Raum gebunden, daher darf hier (im Gegensatz zur Verdächtigung) "room" als Argument nicht fehlen. 18 11 Hinweise Hinweise zu den Spielregeln: • Es gibt verschiedene Cluedo-Auflagen, die sich teilweise in ihren Regeln unterscheiden. Für dieses Protokoll verwenden Sie die Anleitung, die Sie ebenfalls erhalten haben. • Auch wenn die Regeln in der Grundversion bindend sind und so auch umgesetzt werden müssen, können und dürfen Sie gerne weitere, eigene Spielmodi einbauen. Achten Sie darauf, dass diese in den "expansions" erscheinen. • Der Notizblock wird in diesem Protokoll mit keinem Wort erwähnt! Selbstverständlich sollen die Clients die Möglichkeit besitzen, sich auf einem „Block“ Notizen zu machen. Diese Notizen müssen aber nicht an den Server übermittelt werden. Hinweise zur Umsetzung in Java: • Verwenden sie für JSON eine der vielen Bibliotheken, wie bspw. org.json, GSON oder Jackson. • Konfigurieren Sie ihr Java-Projekt mit dem Zeichensatz UTF-8 (Projekteinstellungen). So vermeiden Sie Zeichensatzprobleme mit unterschiedlichen Betriebssystemen (Mac und Linux verwenden i.d.R. UTF-8, Windows die Windows-1252-Kodierung) • Halten Sie sich an Java-Konventionen, insbesondere was Methoden-, Klassen-, Variablen- und Konstantennamen betrifft. Vermeiden Sie dabei Sonderzeichen. • Verwenden Sie Konstanten für häufige Zeichenketten, insbesondere für das Protokoll. • Beobachten Sie ihre Systemlast. Wenn ihr Spiel eine moderne CPU zu 100% auslastet, haben Sie eine fehlerhafte Schleife (Endlosschleife?) irgendwo in Ihrem Programm. Verwenden Sie jvisualvm um herauszufinden, wo ihr Programm zu viel Rechenzeit verbraucht. 19