Registriert: Do Mär 06, 2003 15:27 Beiträge: 281 Wohnort: Bochum
Also ich habe nun mein UDP-Netzwer programmiert und getestet und herausgefunden, das es VIEL zu lahm ist!
Ich bitte euch nun kurz durchzulesen wie es funktioniert und mir evtl. verbesserungsvorschläge zu schicken!
--Also ich nutze WinSock2 und das Protokoll UDP--
Der Generelle Aublauf eines Clients pro Frame:
-Der Client hat eine Liste von Spielern wo jeweils relevante dinge
gespeichert werden (Position...)
-Der Client schickt dem Server Welche Tasten gedrückt wurden
-Der Client emfängt alle Daten die er vom Server bekommen hat die die
Zustände(Position) anderer Spieler angeben und aktualisiert seine Liste
-anhand dieser Liste malt er nun alle Spieler auf den
Bildschirm
Der Generelle Aublauf eines Servers pro Frame:
-Der Server fragt alle Messages(Tastenwerte der Player/ Wenn ein Player
hinzukommt) ab und speichert z.B die neuen Tastenwerte für jeden Spieler
-Nun Aktualisiert er alle Spieler(Bewegungen anhand der Tasten)
-Als Letztes schickt er alle Infos über einen Player an alle anderen
Player(Neue Pos und so), SOFERN diese sich seit dem letzten Frame
verändert haben!
Was für nen Game isses denn ? (Genre)
Wie sehen die Daten aus die gesendet werden ? (Nur ID's für bestimmte Aktionen oder ganze Strings...)
Benutzt du Multithreading ?
Bekommt jeder Spieler alle Daten geschickt, auch wenn er die anderen Spieler nicht "sehen" kann ?
Fragen über Fragen
_________________ Knowledge is Power - So ask if you want to become powerful
so wie du das beshcreibst, klingt das sehr nach einem absolut synchronem spiel - etwa PBM-Schach. und auch dort müssen nur die züge nicht aber die frames synchron laufen. bedenke: das Spiel muss für alle Spieler nur am Anfang und am Ende komplett synchron sein - wäre jedenfalls komisch, wenn dem nicht so wäre. Es empfiehlt sich also meistens immer aus den letzten Informationen die der Server gegeben hat neue Positionen etc. zu Interpolieren. Das Problem ist, dass das je nach Spiel sehr unterschiedlich ausfallen kann, d.h. du musst wie Chendrak bereits sagte etwas konkreter werden.
Registriert: Do Mär 06, 2003 15:27 Beiträge: 281 Wohnort: Bochum
Also ich habe das ganze an einem sehr primitiven spiel getestet und noch net auf mein game übertragen,weil das bei diesem test schon sooooo lahm war!
Das Test-Game war einfach, das jeder Client einen Kreis bewegen durfte und
das halt pro Client ein Kreis da ist!
Demnach waren die Daten auch sehr klein:
-der client schickt dem server immer 4 boolean für seine tasten und einen
byte als erkennungsID.
-und der server schickt jedem client einmal pro frame die pos(2 single) und
diese erkennungsID
Die ganzen andere Fragen(ob ich auch schicke wenn einer den anderen net sieht) fallen bei diesem Primitiven Test weg! Es werden wie oben schon gesagt immer an jeden die PositionsDaten vom Server geschickt WENN sie sich geändert haben!.....Das kann doch nicht sein, dass das dann bei 2 spielern selbst im lokalenNetz langsamer wird und ihr solltet mal sehen wie lahm das übers i-net läuft!
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Multithreading für die Netzwerkkomunikation wäre evtl. eine Überlegung wert, da das Spiel ja nicht komplett still stehen soll sobald die Netzanbindung (Disconnect oder einfach nur langsam) Probleme hat. Sobald du dann nämlich einen Timeout (wg. Disconnect) bekommst, dann bleibt nicht gleich die gesammte Anwendung stehen sondern nur deine Mitspieler. Das könnte auch der Grund sein warum es so schnell bei dir lief. Weil du einfach zu lange aufs Netzwerk warten musstest.
Ich würde an deiner Stelle aber auch keine Tastenwerte zum Server schicken. Ich würde die Tasten bereits auf dem Client in die Positionen umwandeln und dann die Aktionen zum Server schicken. Als Aktion versteht sich. Position verändert. Geschossen. etc.
Damit versteht sich auch, dass der Server alle Positionen außer der Eigenen aktualisiert. Denn die kennst du ja bereits. Somit könntest du Bandbreite sparen. Und die Antwortzeit auf einen Tastendruck wäre auch nicht so hoch. Das bringt auf jeden Fall noch mal richtig an Geschwindigkeit beim Ausführen. Du müsstest dabei dann auch darauf achten, dass die Spiele in irgendeiner Art und Weise synchronisiert werden. Sonst laufen die Spiele auseinander. Sprich genau dann wenn ein PC nicht so leistungsstark ist.
Du solltest auch nur die Positionen updaten wenn sie sich geändert haben und nur die Sichtbaren Spieler wäre evtl auch noch eine maßnahme. Aber das kommt immer darauf an wie viel Intelligenz du in den Server stecken willst. Selective Update (Nur veränderte Werte senden) ist dabei aber schon fast in muss.
PS: Du kannst im gegenzug dein Protokoll von TCP auch auf UDP umstellen. Das Arbeitet ein wenig anders und spart auch noch mal Bandbreite. Bei UDP wird nicht sichergestellt, dass die Pakete auch tatsächlich ankommen. Bei TCP kann es sein, dass das Paket mehrmals gesendet wird sofern keine Bestätigung (vom TCP Protokoll) gesendet wird. Das erleichert die Entwicklung (bei UDP) aber nicht unbedingt, da du in kauf nehmen musst, dass nur die Hälfte der Pakete ankommt.
Registriert: Do Mär 06, 2003 15:27 Beiträge: 281 Wohnort: Bochum
@Lossy:
Danke für den Ausführlichen Beitrag, aber du hast mir damit nur sehr wenig geholfen!Hättest du meinen Ersten Beitrag durchgelesen wüsstest du das ich die Netzwerk-Engine bereits auf UDP programiert habe, deshalb hilft mir Multithreading nur beschränkt weiter.
Ausserdem hab ich deshalb auch keine Connection die abbrechen könnte.
Ganz abgesehen davon das ich das in meinem MINI_NETZWERK_TEST_GAMES garnicht reinprogramiere, wird in mein richtiges Game später eine interpolation reinkommen, so das die Clients die Werte die sie voneinander haben weiter "simulieren" so lang bis sie aktuellere Werte vom Server bekommen!....Der Vorteil dabei ist im Übrigen, dass ic keine Tricks benutzen muss um einen Dedicated-Server zu starten, der also keinen Client gleichzeitig in sich hat, sowie es ist wenn ein belieber Spieler n Server startet!
Das System das die Clients nur ihre Tasten schicken ist demanch auch in Ordnung, denn so bekommt der Server die Aufgabe die er eigentlich haben sollte, nämlich der Koordinator zu sein und die "einzig wahren" Positionen der ganzen Spieler hat, die er aufgrund der Tasten die er bekommt verändert!
Ganz abgesehen davon benutzt Quake das gleiche Prinzip, also das die Clients nur ihre Tasten etc schicken!
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Okay. Hab ich überlesen, dass du das bereits auf UDP laufen hast.
Dennoch finde ich das Prinzip, dass der Server die Tastendrücke in Positionen umrechnet reichlich Suboptimal. Ungeachtet der Tatsache, dass es in Quake verwendet wird. So etwas muss allerdings jeder für sich entscheiden. Und ich persönlich würde es halt anderes machen.
Zum Thema Thread. Ich verstehe nicht ganz warum du das nicht einsetzten kannst?
@Extrawurst:
Ich kenne es bisher auch nur so, dass der Client seine neue Position an den Server schickt, der überprüft ob sich der Spieler dorthin bewegen kann/darf und dann entsprechende Positionspakete an alle Spieler im sichtbaren Bereich zurücksendet.
Naja, egal, zum testen wird das mit den Tastendrücken ausreichen.
So wie du das ganze beschrieben hast, hört es sich eigentlich ganz gut an und ich glaube eher der bremsende Faktor liegt irgendwo in deinem Code.
_________________ Knowledge is Power - So ask if you want to become powerful
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Ich habe mir das gerade noch mal richtig angesehen was du ganz oben geschrieben hast. Und ich vermute mal sehr stark, dass es daran liegt, dass du Grafikberechnungen und Datenübertragung in ein und dem selben Thread machst. Du empfängst deine Daten und anschließend aktualisierst du deine Liste. Wenn das alles fertig ist dann erst zeichnest du es. Die Liste zu aktualisieren kann dabei vernachlässigt werden. Was das größere Problem sein wird ist wohl die Übertragung. Für eventuelle Antwortzeiten bleibt ja die Anwendung stehen. Es empfielt sich sowieso die Renderung und die Netzwerkübertragung zu trennen (auch wenn du es nicht höre möchtest Threads). So kannst du wärend noch Daten übertragen werden schon das noch aktuelle Bild zeichnen. Wenn du dann alles komplett hast dann aktualisierst du deine Spielestaties.
Gibt es etwas was du bei jedem Frame überträgst?
Also so etwas in der Art wie. "Bin noch da. Hat sich etwas geändert?"
Das habe ich nämlich aus deiner Aufzählung oben nicht so ganz herraussehen können.
Mir ist noch etwas aufgefallen. Du sagst du 4 Booleans für die Tasten schickst. In Delphi ist ein Boolean mindestens einen Byte groß. Wenn nicht sogar noch größer. Es würde sich an der Stelle anbieten, dass du direkt die Taste sendest. Bzw. eine komplette Liste mit Tasten.
Ich weiß auch nicht wie du das sendest. Aber kannst du mit Sicherheit ausschließen, dass die einzelnen Daten jeweils als ein Paket gesendet werden? Also bei Indy weiß ich es auch nicht 100%tig wie die das machen aber es gibt eine Methode SendInteger oder so ähnlich. Und dabei bin ich der Meinung, dass er in ein Paket lediglich diesen Integer packt. Was reine Bandbreitenverschwendung wäre. Evtl passiert bei dir ähnliches.
Registriert: Do Mär 06, 2003 15:27 Beiträge: 281 Wohnort: Bochum
Ja also ich mache in der tat alles in einem thread, rendern und empfangen!
Ich benutze allerdings Blockende-Sockets und dachte das es dann klappen müsste, da der Socket bei recvfrom sofort zurückkommt wenn nichts da ist!
ja es gibt sachen die ich jedesmal im frame sende,
der client sendet:
-diese vier tasten in EINEM PACKET
Code:
type
PLAYER_MD=packed record
links:Boolean;
[usw.]
end;
der server sendet einmal pro frame:
-die aktuellen positionen (2x single) jedes players in EINEM PACKET
an alle player WENN SICH DIE POS VERÄNDERT HAT(seit dem letzten
frame)!
PS:Wisst ihr ob es sich lohnt Multicasting zu verwenden? ist das verbreitet genug, so das man davon ausgehen kann das die meisten das unterstützen?
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Okay. So genau kenne ich mich den WinAPI-Sokets auch nicht aus. Aber das müsste so eigentlich keine Proleme machen. Wie das aber mit der Geschwindigkeit deiner Sokets ist dazu kann ich dir nichts sagen.
Evtl. solltest du die Sokets direkt mal so Testen. Also ohne Rendern mal direkt Pakete verschicken und (oder) empfangen. So 2000(00) Stück oder so. Und dann mal die Zeit und Prozessorauslastung testen. Dann weißt du genau wie lange es dauert und wenn sich dein Przossor dabei langweilt, dann weißt du auch, dass er zu lange auf Hardware warten muss. Wenn dem so ist solltest du es in der Tat auslagern.
Registriert: Mo Sep 23, 2002 19:27 Beiträge: 5812
Programmiersprache: C++
Da ich in meinem NapalmBomber3D ja auch nen Multiplayermodus drin hab,kann ich dir da evtl. ein wenig helfen.
Zuerst wollt ich es nämlich so ähnlich machen wie du und nur dann die Spielerposition an den Server senden,wenn diese sich von der aktuellen unterschied.Also hab ich in den MainLoop ne einfache Abfrage gemacht,ob dies der Fall ist und diese dann an den Server gesendet.Komischerweise war das dann aber verdammt lahm.Der Grund dafür ist ganz einfach : Der Spieler drückt ja nicht nur ne ms lang auf die Taste,sondern lässt diese über nen längeren Zeitraum gedrückt.Bei 50fps würde das dann möglicherweise bedeuten,das die Position (da die Bewegung ja aufgrund des TimeBasedMovement an jedem Frameende berechnet wird) bis zu 50x pro Sekunde zum Server gesendet wird.Problem ist hier nicht die Datenmenge die ja recht gering ist,sondern die Anzahl der Packet.Bei dieser Methode werden sehr viele Packete gedroppt (oder neugesendet,allerdings nur bei TCP/IP).Dadurch wird die Sache im Endeffekt total langsam.
Lösen lässt sich das ganz einfach mit einem Timer,der die Spielerdaten unabhängig ob verändert oder nicht in permanenten Intervallen sendet.In NB3D sendet jeder Client alle 20ms seine aktuelle Position an den Server (Intervall lässt sich aber per INI verändern).Diese Methode funzt einwandfrei und die Bewegungen laufen auf allen Rechnern flüssig ab.Probiers also mal so und schon sollte es so funzen wie du willst.
Registriert: Do Mär 06, 2003 15:27 Beiträge: 281 Wohnort: Bochum
meinst du das das bei mir auch klappt ?
ich sende ja nicht die playerpositionen, sondern die tasten die ein player grade drückt, dies tu ich allerdings wirklich jedesmal pro frame.....
Registriert: Mo Sep 23, 2002 19:27 Beiträge: 5812
Programmiersprache: C++
Wie gesagt spielt es keine Rolle wie viel du sendest, sondern wie viele Packete du sendest.Ob das Packet nun 4 Byte oder 40 Byte groß ist dürfte da nicht viel dran ändern.Wenn du allerdings pro Frame dutzende Packete verschickst,was bei deiner Methode der Fall sein dürfte,dann werden da jede Menge Packete gedroppt,weshalb alle Bewegungen langsam wirken.Zumal der Rechner ja auch noch mit anderen Sachen beschäftigt ist.
Ob die Sache mit dem Timer die perfekte Lösung ist,wage ich zu bezweifeln,aber wenns funzt dann spricht eigentlich nix dagegen.
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Vielleicht wäre es da sogar sinnvoll das OnKeyDown event zu benutzen um deine Tasten zu senden. Also, dass du die Tastendrücke nur sendest sofern denn auch tatsächlich Tasten gedrückt worden. Oder im Zweifelsfall Positionen statt Tasten zu senden. Und die dann auch nur sofern sich etwas verändert hat. Aber das kann man ja mittels Timer abfragen und ggf. etwas senden oder halt nichts tun.
Mitglieder in diesem Forum: 0 Mitglieder und 7 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.