Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

04.08.2015, 08:43

Network Multiplayer Design

Guten Tag,

ich habe gestern mal angefangen mich abseits von Onyx mit der SFML zu beschäftigen. Dabei interessiert mich vor allem das Thema Netzwerk Multiplayer, deswegen liegt hier auch mein Hauptaugenmerk drauf.
Bevor ich nun großartig anfange zu programmieren, wollte ich mir erstmal mein grundlegendes Design für die einzelnen Abstraktionsschichten erarbeiten.

Letztendlich gliedert sich das Ganze ja in die üblichen Bereich, lediglich Netzwerk kommt hier hinzu. Dementsprechend haben wir also:

- Player Input
- Game Logik
- Game Darstellung
- Netzwerk Replikation

Vorweg, ich habe eine abgeschlossene Ausbildung als Fachinformatiker und bin mit den grundlegenden Dingen der Netzwerktechnik vertraut. Deswegen richtet sich meine Frage auch nicht darauf, wie funktioniert Netzwerk, sondern wie eher wie designe ich mir mein Netzwerk Multiplayer Game richtig.

Was habe ich genau vor?
Vll kennt es noch jemand, ich plane eine Wirtschaftssimulation in Richtung "Die Gilde". Dabei fallen einige Problemfälle für Netzwerkspiele schon einmal Weg. Ich benötige keine Validierung von irgendwelchen Spielerpositionen oder ähnliches. Die Spieler funktionieren etwa so wie in üblichen RTS. D.h. man schaut aus der Vogelperspektive auf das Geschehen und bewegt dabei lediglich die Kamera.
Das Spiel wird sehr simulationslastig. D.h. der Server errechnet viele Dinge und muss dabei natürlich immer die Clients mit benachrichtigen.
Beim Spielbeginn wird festgelegt, wie viele Spieler es gibt (Anzahl der Clients in der Lobby). Während des Spiels können keine weiteren Clients dem Spiel beitreten, es können aber jederzeit Spieler ausscheiden, sollten sie entweder ausscheiden oder das Spiel von sich aus verlassen. Das Spiel soll load/savable sein, d.h. dass man das Spiel später zu dem gespeicherten Stand fortsetzen kann.

Das Spiel soll dabei aber nicht nur im Netzwerk spielbar sein, sondern auch als Singleplayer.

Meine bisherigen Ideen:
Grundlegend wird es wohl States geben, die die einzelnen Bereiche wie Hauptmenü, Lobby, Game abdecken.
Aus dem Hauptmenü kommt man entweder in die Lobby oder direkt ins Game.
Ist man in der Lobby wird entsprechend der Auswahl im Hauptmenü (Host Game, Join Game) der Netzwerk"dienst" gestartet. D.h. entweder erstelle ich ein Netzwerk Objekt Server (mit listener und mehreren Sockets) oder Client (mit Socket).
Dazu habe würde ich verschiedene Netzwerk Rollenobjekte erstellen und diese an die entsprechenden GameStates übergeben.
Local
Server
Client

Local hat überhaupt keine Netzwerkfähigkeit und wird entsprechend für den Singleplayer benutzt.


An sich würde ich TCP favorisieren, da ich hier garantiert bekomme, das alle Nachrichten in der korrekten Reihenfolge ankommen, und ich mich so schon einmal um eine Sache weniger kümmern muss.
Grundlegend hätte ich nun einen GameState, der polymorphe Pointer auf meine Netzwerkrolle hält. Die einzelnen Sockets/Listener innerhalb der Rollen dürfen die Game Loop nicht blockieren, d.h. es werden grundsätzlich über Polling eingehende Nachrichten abgefragt. Ausgehende Nachrichten würden dementsprechend ebenso asynchron verschickt werden.
An sich bin ich mit dem System nicht ganz zufrieden, da ich lieber auf Events reagieren würde, als ständig alle Sockets abzufragen.
D.h. hier würde ich das Empfangen in einen eigenen Thread auslagern und mir so entsprechende Events generieren.

Kommen wir also zum Senden. An für sich würde ich hier einen blockierender Ansatz verfolgen. Dadurch wäre sicher gestellt, dass der Server und die Clients immer einen synchronen Stand haben. D.h. hat ein Client Empfangsprobleme, würden der Server und alle anderen Clients auf dem letzten Stand gehalten werden und könnten so bei einem Timeout korrekt weiter laufen. Ist hier meine Überlegung korrekt oder bringt das bisher nicht bedachte Probleme mit sich?
Ich könnte natürlich auch den asynchronen Ansatz verfolgen, hätte dabei aber weniger Kontrolle über etwaige OutOfSync Probleme.
Was man dabei natürlich auch bedenken muss, ist die Tatsache das die äußere Message Loop (für den Empfang der Window Messages und das Rendern) natürlich auch nicht blockieren darf, damit es für den User nicht so scheint als würde das Game freezen. Dementsprechend hätte man hier generell schonmal 2 Threads (Render und Game Logik). Bei der non blocking Variante könnte ich alles in einem Thread auslesen, müsste allerdings jeden Frame sicher gehen, dass die Clients noch synchron laufen. Wie gut das mit SFML handlebar ist, weiß ich noch nicht.
Was bietet sich denn hier idealer Weise an?

mfg

2

04.08.2015, 09:48

Ich verzichte gern sowas wie eine lokale Version wenn ich Mutliplayerspiele mache. Man kann immer über die Loopadresse gehen wenn man local will.

Würde Client und Server machen auch wenn Singleplayer gerade.

Wenn du peer2peer machen willst, so kannst du einen Host bestimmen, der dann auch gleichzeitig zu seinem Clienten einen Server startet der dann mit allen kommuniziert und mit sich selbst natürlich.

Wenn du dann natürlich sowas wie eine Serverliste haben willst oder Matchmaking kannst du ein extra Server-Programm noch schreiben, der nur zur Vermittlung da ist. Bzw. wo alle hallo sagen die online sind.

Am Ende würde ich dann eine peer2peer aufbauen im Grunde zwischen allen Clienten. Dann braucht man die Verbindung zum extra Server nur Kurzzeitig und die Last trägt ein Spieler. Heute sollte das nicht mehr so das Problem sein und du must keinen extra teuren Server hosten.

Und natürlich am Besten dem Spieler offen lassen auch direkt die IP eingeben zu können. Wenn mal die Server down sind oder beschliest diesen extra Server nicht mehr zu betreiben, dann kann man zumindest als Spieler noch miteinanderspielen über eine direkte IP.

Ansonsten ist es natürlich immer Klug Logic vom Rendering zu trennen. Damit man sowas überhaupt gut umsetzen kann. Beispielsweise eine Dedicated machen kann.

Kleiner Tip wäre diese Biblio: https://github.com/binary1248/SFNUL

War damals mit SFML in Verbindung. Heute kann man sie sogar für egal was verwenden. Echt tolle Library. Wirklich simple.

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »TypeOverride« (04.08.2015, 09:55)


3

04.08.2015, 12:54

Hallo, danke für deine schwer verständliche Nachricht ;)
Ich will weder eine Serverliste noch irgendeinen Matchmaking Stuff.
Letztendlich plane ich den Multiplayer im lokalen Netz. Aber auch hier werde ich keine Serverliste generieren, sondern verlange für einen Join die Eingabe der IP. Zumindest erstmal.

Die Idee mit der Loopback Adresse hatte ich auch, allerdings habe ich das auch wieder verworfen, da ich einen Player direkt im Spiel als "Server Owner" identifizieren möchte, der für das Laden/Speichern verantwortlich ist, und für andere Dinge wie z.B. die Spielgeschwindigkeit einstellen und so weiter verantwortlich ist.
Könnte man sicher auch anders lösen, sodass immer der zuerst beigetretene Spieler der Owner ist.

Aber generell stellt sich mir halt immer noch die Frage, wie ich das Networking am Besten handhabe. Wäre über generelle Erfahrungen dankbar ;)

4

04.08.2015, 15:00

Im LAN kannst du ein UDP-Paket an eine Adresse in FF02::/16 senden. Du musst die Adresse nur festlegen und im Server die Option IPV6_ADD_MEMBERSHIP mit der Adresse setzen, dann kann der Server das Paket empfangen und etwas zurücksenden. So kannst du alle Server im LAN auflisten.
Cube Universe
Entdecke fremde Welten auf deiner epischen Reise durchs Universum.

5

04.08.2015, 15:26

Ist auch nicht das, was mich eigentlich interessiert. Gibt ja entsprechende Methoden, wie man an eine Server Liste kommt (Broadcast z.B.). Das ist jetzt aber alles völlig sekundär und an meiner Frage vorbei geschossen.
Was mich eben grundlegend interessiert, wie handle ich senden und empfangen SINNVOLL auf dem Server und dem Client. Die Rahmenbedingungen die ich im 1. Post aufgelistet habe gelten nach wie vor!

Tobiking

1x Rätselkönig

  • Private Nachricht senden

6

04.08.2015, 18:57

An "Out of sync" wirst du im gewissen Maße nicht vorbeikommen. Zwischen "Client bekommt aktuelle Daten vom Server" und "Aktion vom Client kommt am Server an" können sich die Daten auf dem Server bereits wieder geändert haben und die Aktion ist ungültig. Deswegen gibt es bei Datenbanken Transaktionen, die zurückgerollt werden wenn sich der Datenstand zwischendurch so ändert das eine Aktion invalid wird.

Meiner Meinung nach ist das Ablehnen einer Aktion aber für den Spieler sehr unschön. Die Aktion einfach durchführen hingegen kann zu Inkonsistenzen führen, z.B. wenn zwei Spieler gleichzeitig die letzten Einheiten einer Ware kaufen. Ich würde daher wohl den Weg wählen solche Situationen zu sperren, indem z.B. nicht mehrere Spieler beim gleichen Händler sein können etc.

Ansonsten sehe ich eigentlich nur Übertragung blockierend im Thread oder asynchron als Möglichkeit. Das du den Render Thread nicht blockieren willst, hast du ja selbst schon erkannt.

Nox

Supermoderator

Beiträge: 5 272

Beruf: Student

  • Private Nachricht senden

7

04.08.2015, 19:17

Wenn ich meinen Senf dazu geben darf:
1. bitte Bitte BITTE kein peer2peer (sag es nur, weil es hier in den Raum geworfen wurde. Der zuerst genannte Server-Client vermeidet viele konzeptionelle Probleme).
2. Von Blocking würde ich absehen, weil sobald ein Client die Verbindung verliert, steht alles still.
3. Persönlich habe ich zum Empfangen sehr gute Erfahrungen mit eigener Thread+select+packet queue/events gemacht.
4. OoS lässt sich zwar vermeiden (siehe heartbeat concept), aber es kommt zu einem Preis. Alternativ kann man auch einfach sie in Kauf nehmen. Vorallem wenn man statt Aktionen immer nur die geänderten Zustände verschickt.
PRO Lernkurs "Wie benutze ich eine Doku richtig"!
CONTRA lasst mal die anderen machen!
networklibbenc - Netzwerklibs im Vergleich | syncsys - Netzwerk lib (MMO-ready) | Schleichfahrt Remake | Firegalaxy | Sammelsurium rund um FPGA&Co.

8

04.08.2015, 19:33

An "Out of sync" wirst du im gewissen Maße nicht vorbeikommen. Zwischen "Client bekommt aktuelle Daten vom Server" und "Aktion vom Client kommt am Server an" können sich die Daten auf dem Server bereits wieder geändert haben und die Aktion ist ungültig. Deswegen gibt es bei Datenbanken Transaktionen, die zurückgerollt werden wenn sich der Datenstand zwischendurch so ändert das eine Aktion invalid wird.

Meiner Meinung nach ist das Ablehnen einer Aktion aber für den Spieler sehr unschön. Die Aktion einfach durchführen hingegen kann zu Inkonsistenzen führen, z.B. wenn zwei Spieler gleichzeitig die letzten Einheiten einer Ware kaufen. Ich würde daher wohl den Weg wählen solche Situationen zu sperren, indem z.B. nicht mehrere Spieler beim gleichen Händler sein können etc.

Ansonsten sehe ich eigentlich nur Übertragung blockierend im Thread oder asynchron als Möglichkeit. Das du den Render Thread nicht blockieren willst, hast du ja selbst schon erkannt.

Vielen Dank für deine Antwort,

Datenbanken nutze ich gar nicht.

Das "Out of Sync" in gewissem Maße entstehen kann, ist mir klar. Die Daten, die an den Client gesendet werden, dienen ja rein der visualisierung (und im bedingten Maße auch der validierung der Aktionen, klar). Und hier gehe ich dann auch nach dem Prinzip "wer zuerst kommt, malt zuerst". Kann zwar in gewissen Bereichen nicht ganz fair sein, aber für meine Zwecke reicht mir das vollkommen. Letztendlich plane ich ja, dass der Spieler Aktionen an den Server sendet und der Server ist dann auch für die Reaktion darauf zuständig. Wenn die Reaktion bedeutet, dass die Aktion abgewiesen wird, weil der Client noch die alten Daten hatte, dann ist das eben so. Da es sich weder um ein Reaktionsspiel handelt, noch es wirklich wichtig ist, wo sich welche Einheit zur Zeit befindet, ist dieser delay denke ich verschmerzbar.

Ich bastel momentan an einer Lösung, wie ich mir das vorstelle. Ist nunmal die erste Netzwerk Anwendung die ich schreibe, ich denke hier mache ich die größten Fortschritte durch trial and error ;)


Wenn ich meinen Senf dazu geben darf:
1. bitte Bitte BITTE kein peer2peer (sag es nur, weil es hier in den Raum geworfen wurde. Der zuerst genannte Server-Client vermeidet viele konzeptionelle Probleme).
2. Von Blocking würde ich absehen, weil sobald ein Client die Verbindung verliert, steht alles still.
3. Persönlich habe ich zum Empfangen sehr gute Erfahrungen mit eigener Thread+select+packet queue/events gemacht.
4. OoS lässt sich zwar vermeiden (siehe heartbeat concept), aber es kommt zu einem Preis. Alternativ kann man auch einfach sie in Kauf nehmen. Vorallem wenn man statt Aktionen immer nur die geänderten Zustände verschickt.

Nee, nee. p2p kam für mich gar nicht erst in Frage. Hätte ja schließlich auch zur Folge, dass alle Clients gleichberechtigt sind und das möchte ich ja unbedingt vermeiden.
Mich würde mal eine erweiterte Ausführung von Punkt 3 interessieren ;)

mfg

Hello_Kitty!

unregistriert

9

04.08.2015, 21:31

Vorweg, ich habe eine abgeschlossene Ausbildung als Fachinformatiker und bin mit den grundlegenden Dingen der Netzwerktechnik vertraut.

Du musst die Daten zu einem Packet schnüren und dann über OSI 0 (bit abstraction layer) an die ip_addr des Empfängers schicken.

Hoffentlich hilft dir das weiter...


mfg

10

04.08.2015, 21:37

Vorweg, ich habe eine abgeschlossene Ausbildung als Fachinformatiker und bin mit den grundlegenden Dingen der Netzwerktechnik vertraut.

Du musst die Daten zu einem Packet schnüren und dann über OSI 0 (bit abstraction layer) an die ip_addr des Empfängers schicken.

Hoffentlich hilft dir das weiter...


mfg

...

Also manchmal finde ich dein getrolle ja echt witzig, aber muss man sich immer und überall über alles und jeden lustig machen? Aber bevor du das nächste mal sowas ablieferst, solltest du dich vll mit der Materie vertraut machen.

Werbeanzeige