Multiplayer: Mapübertragung ; Server - Client

    • GM 8

    Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

    • Multiplayer: Mapübertragung ; Server - Client

      Hallo!
      Ich arbeite gerade an einem Spiel mit Multiplayer(Server - Client system). Nach dem Verbinden, soll dem Client die gesamte Map übertragen werden ( Blockartig, in einem Grid gespeichert). Diese ist jedoch ziemlich groß(1000 x 300). Wie kann ich das jetzt möglichst schnell anstellen? Wie kann ich die Map übertragen, ohne dass es Minutenlang dauert. Und wie kann das anstellen ohne dass der Server totale Framerateeinbrüche bekommt?
      Ich danke für alle Tips & Anregungen, hoffentlich auch von Leuten, die ein bisschen erfahrung damit haben.
      //edit:
      EDIT: Eh, wtf? Das ist doch sicher nicht die "hilfreichste" Antwort hier, oda? lol
      Ist es auch nicht, hab mich im Beitrag geirrt :rolleyes:



      // Ich habe mich schlussendlich einer Mischung aus den genannten Lösungen entschieden. Ich übertrage die Map in mehreren Chunks. Ich übertrage sie als String, wobei ich die ID's der Blöcke mit chr() in ein Zeichen umwandle, damit auch alle nur 1Zeichen verbrauchen, um sie Später wieder auszulesen, und mit ord() zurückzuwandeln.
      //Das chr(0) Zeichen wird von der 39DLL als Stringende interpretiert, da musste ich immer 1drauf addieren!

      Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von Partik ()

    • Wasgenau meinst du denn mit "Map"? Eine eigene Form eine Spiel-Karte abzuspecihern oder doch die Datenstruktur ds_map?
      Wenn letzteres der Fall ist, dann ist es einfach denn es gibt die Funktion ds_map_write(id) die die gesamte information in einen String packt den man dann direkt nach dem Verbinden auf dem andeeren Computer wieder in eine map zurückverwandeln kann.

      Willst du auf diese Drachen und -eier klicken?
      Sie werden sich freuen ;)
    • Das Problem ist ziemlich schiwerig. Wenn du nur zwei werte hättest, also -1 und 1 könntest du ganz einfach binär rechnen und die zu übertragende Datenmenge wäre nur noch 37,5 kB. Wenn du aber auch andere Werte brauchst... naja dann geht das schlechter.
      Wievielen Pixeln entspricht denn ein solcher Block auf dem Bildschirm? Du könntest nämlich die Karte in Sektoren unterteilen und während des Spielens, Bereiche der Karte laden (so funktionieren diese ganzen browser-mmorpgs).

      Willst du auf diese Drachen und -eier klicken?
      Sie werden sich freuen ;)
    • Also wie gesagt kenn ich ein paar Spiele die genau so funktionieren. Auf jedenfall wird es vom programmiertechnsichen wohl viel schwieriger werden ein ausreichendes Kompressionsverfahren zu entwickeln.
      Wie es mit der Performance aussieht lässt sich sehr schwer sagen allerdings müsste es ausreichen wenn pro Step ein Block übertragen wird und das belastet das Spiel definitiv nicht.


      EDIT: Eh, wtf? Das ist doch sicher nicht die "hilfreichste" Antwort hier, oda? lol

      Willst du auf diese Drachen und -eier klicken?
      Sie werden sich freuen ;)

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von DragonGamer ()

    • Ja, das wäre eine gute Idee. Ist dein Spiel aber ein mmorpg oder ein anderes Genre? Wenn du nämlich einen Ladebalken beim Betreten von, sagen wir mal "Räumen", in Kauf nimmst, kannst du einfach nur den Teil der Karte des nächsten Raumes übertragen.

      Des weiteren, wird die Karte denn zufallsbasiert erstellt? Da gäbe es nämlich möglichkeiten durchaus absolut zufalls-generiert aussehende Karten zu erstellen aber trotzdem die Möglichkeit zu haben nur mit Hilfe von sehr wenig Daten, die Karte beim Client schlicht zu reproduzieren. Solch eine Technik wenden glaube ich, sowohl Minecraft als auch Anno an, die jeweils ein sogenanntes "seed" nutzen.

      Willst du auf diese Drachen und -eier klicken?
      Sie werden sich freuen ;)
    • Du darfst es dir vorstellen wie Creawo in Online. Das ist zwar nicht das worauf ich hinaus will, aber es lässt es villeicht etwas klarer werden. ICh kann die Karte zudem nicht einfach so wie sie am Anfang mal erstellt wurde übertragen, da sie von den anderen Spielern verändert wird. Der Ladebalken wäre bei 20 Blöcken pro Step über 2 Minuten Lang.
      EDIT: es wird wohl oder Übel auf die Teilübertragung hinaus laufen....
    • Mach es doch einfach so:

      Map erstellen.
      Diese Map zum 1. und letzten mal auf einen Webserver übertragen.
      Mensch der die Karte nicht besitzt connected zu dir und lädt die Map automatisch
      Wenn beide Tschüss sagen und der Host schließt wird die veränderte Map jetzt an den WServer gesandt.
      Dann müssen beide neu laden... im Grunde ist es dann auch egal wer der Host ist.
    • Wie wär's, wenn du nur die Teile der Map anforderst, die du siehst?
      Dann können die anderen Indizes des Grids ja einfach 0 bleiben und sobald der Spieler sich dem Sichtbaren Bereich nähert, sendest du die nächsten paar Blöcke in dem Bereich.
      So sparst du auch unnötiges Senden der Blöcke und der Spieler profitiert von den kurzen Ladezeiten.

      - Tobi97

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Tobi97 ()

    • Map erstellen.
      Diese Map zum 1. und letzten mal auf einen Webserver übertragen.
      Mensch der die Karte nicht besitzt connected zu dir und lädt die Map automatisch
      Wenn beide Tschüss sagen und der Host schließt wird die veränderte Map jetzt an den WServer gesandt.
      Dann müssen beide neu laden... im Grunde ist es dann auch egal wer der Host ist.

      Das funktioniert so nicht. wie gesagt, wird die Map laufend verändert und jemand der zwischendrin einsteigt, soll alle vorherigen Veränderungen mitbekommen.
      Ich glaube ich kann ein Paar Sekunden Ladebalken, und danach eine etwas langsamere übertragung in kauf nehmen.
      Also: zuerst wird der Spawn Bereich übertragen, danach wird während dem Spielen der Rest Stück für Stück übertragen. Das dürfte nur einen geringen Teil der Spielzeit beeinflussen.
      Außerdem kann ich so leere Blöcke beim Senden auslassen.
    • Ich hab ne Idee! Mach es doch einfach so wie am Anfang einen kleinen Raum:
      Chat
      Klamotten
      Alle bereit?
      Falls nötig Waffe.

      Weiß ja nicht welches Genre...

      Und während diesen kleinen Einstellungen einfach die Welt streamen und für die Neueinsteiger
      auch so mit Klamotte Waffe und Losgehts ^^
    • EDIT: während ich diesen Roman verfasste, sind gleich 10 neue Posts in den Thread gekommen. Ignoriert die Zusammenhangslosigkeit, einige dinge haben sich erst jetzt herrauskritalisiert, wie sie zu seien gemeint sind.

      Das ist eine schlechte Idee, nur einen kleinen Satz zur Zeit zu senden. Da geht viel zu viel Performance verloren. Das erste mal übertragen ist ja nicht das Drama.

      Ich würde dir empfehlen alle Werte binär und komprimiert zu versenden. Das geht relativ einfach. Deine Struktur, also ein Grid so weit ich vernehmen kann, mit der GM eigenen Funktion in eine temporäre Datei speichern. ds_grid_save() glaube ich. Das ist binär, und daher an sich schon mal recht klein.
      Diese Datei kannst du dann wieder einlesen und komprimieren - oder andersrum, je nachdem welche Tools du nun gerade brauchst.
      Ich erinnere mich an eine DLL die so einfach wie string_compress( str ) und string_decompress( str ) war, finde sie aber nicht mehr. Musst dich mal umschauen, hat sich sicherlich auch einiges getan.
      Wenn du dann den komprimierten String hast, kannst du den versenden. Verglichen mit Wert nach Wert senden kommst du geschätzt auf 80% Daten Ersparnis - allerdings dauert das Komprimieren auch ein paar Millisekunden - das sollte aber nicht relevant im Verhältnis zur dauer der Versendung sein.
      Auf der anderen Seite verläuft es dann genau Umgekehrt. Empfangen, dekomprimieren, in Datei schreiben und dann mit ds_grid_read() einlesen.
      Diese Lösung wirkt auf den ersten Blick vielleicht ein bissl zusammengeschustert aus, sollte aber gut seine Aufgabe verrichten.

      Wenn du nur die Werte 0 bis 255 in der Tabelle/Grid hast, sieht es noch mal anders aus. Dann würde ich es angehen, wie man es üblicherweise bei zb. Bitmap Bildern macht. Um eine String-Repräsentation deine Map zu bekommen, würde ich den String folgendermaßen aufbauen.
      Die ersten beiden Werte lass die Dimension sein. Wie Breit und wie Hoch ist die Tabelle. Wenn die beiden Werte gesetzt sind, können danach einfach Byte für Byte die Werte folgen, ohne Seperatoren für neue Reihen, da sich ja aus der Breite des Grids errechnen kann, wann ein Wert ein eine neue Reihe gehört. Werte wendelst du einfach mit ansi_char() um. Zurück gehts btw mit ord().
      Diesen String dann komprimieren und absenden. Diese Lösung ist, logischer Weise, 4 mal kompakter als die oben genannte, da ein Byte nuneinmal ein Byte groß sind, reals, wie in Grids genutzt, meines Erachtens 4 Byte füllen.


      Für die laufenden Änderungen hätte ich zwei Lösungen: eine schnelle und eine sparsame.
      Wenn du Geschwindigkeit brauchst, also, dass Änderungen im Gelände sofort beim gegenüber ankommen, würde ich die Änderungen einfach so wie sie sind senden. Einfach die 3 relevanten Werte (x, y, Wert) sofort, wenn die Änderung passiert ist, versenden. Das ist reaktionsschnell, und akzeptabel, wenn die Änderungen nicht in großen Mengen auftreten.
      Wenn man da zb. an Minecraft denkt, wäre das die richtige Lösung. Es geschieht nie mehr als 1 bis 2 Änderungen am Gelände pro Sekunde. Außerdem sollen die sofort beim gegenüber ankommen.

      Die alternative ist es, ein Buffer der Änderungen einzurichten. Dies ist relevant, wenn viele Änderungen auf ein mal auftreten können. So zb. wenn ganze Landstriche geändert werden müssen.
      Hier würde es folgendermaßen verlaufen: wenn Änderungen geschehen, werden die erst mal in einen Zwischenspeicher, einen Buffer, gespeichert. Dort steht dann, dass dies und jenes sich geändert hat.
      Wenn der Buffer entweder ein gewisses Limit an große überschritten hat, oder seit dem letzten Update schon eine gewisse Zeit vergangen ist, sagen wir mal 5 Sekunden, wird der Buffer komprimiert und Versand. Hier stelle ich mir ein Vorgehen wie bei der zweit genannten Lösung für die Initialisierung vor.

      Auch ein paralleles System wäre möglich. Wenn wenige Änderungen geschehen, einzeln, unkomprimiert und direkt senden. Wenn große Änderungen wie die Versetzung eines Berges anstehen, sende die als komprimierter Batch von Änderungs-befehlen.


      Ich habe mich jetzt recht mit Codeschnippseln zurück gehalten, da dies das Expertenforum ist und von daher nicht notwendig sein sollte. Hoffe es hat dir geholfen.

      MfG SDX

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von SDX ()