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

    • 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.

      Wie gesagt 9.600.024 Zeichen Lang...
      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.

      Das wiederum wäre möglich, ich könnte, um nicht meine komplette struktur zu verändern statt -1, 0 verwenden da die 0 Momentan eh nicht als BlockID vor kommt. Macht immernoch 300.000 Bytes, ca 0,29MB(!!). Das ist aber für den Anfang eine große einsparung. Versendet man diesen wieder Stück für Stück, ist man bei 120Steps/s und 20Paketen/Step immernoch bei 2minuten übertragungszeit, das lässt sich mit größeren Paketen verbessern. Der Ansatz gefällt mir zumindest sehr gut! Wie sehr kann man so eine Zeichenkette denn komprimieren?
      EDIT:
      Für die laufenden Änderungen hätte ich zwei Lösungen: eine schnelle und eine sparsame.

      Das Löse ich genauso wie die Übertragung von Laufen und Springen. Wird direkt übertragen(x,y,id).
    • Erstens würde ich Empfehlen, dass Anfängliche senden/laden auf ein mal zu verrichten. 39Dll unterstütz Threads, und 0.3 MB sind bei Modernen Verbindungen in Bruchteilen von Sekunden Versand. Selbst bei ISDN haben wir das innerhalb von 30 Sekunden runter. Und ich kann dir sagen, dass diese Leute gewohnt sind, dass online spiele in der regel nicht Spielbar sind. Und wenn, dass man dann schon viele Minuten an Ladezeiten in kauf nimmt.

      Bei der Kompression gibt es unglaublich viele Faktoren. Wenn du reell nur die Werte 0 bis.. sagen wir mal 16.. im Gebrauch hast, solltest du bei den meisten Algos nur noch 10% vom Original haben.
      Wenn du den gesamten Umfang ausnutzt, also 0 bis 255, kommst du auf ca. 60% - Das ist aber sehr, sehr abhängig von Mondphasen und biospherischen Zyklen.

      Empfehlen kann ich nur gzip, das ist mit einer der schnellsten und effektivsten. Du musst natürlich immer ein Auge darauf halten, ob es einen Wrapper für GM gibt. Aber wenn möglich, halte dich an pigz mit geringster Kompressionsstufe. Das ist laut eines Benchmarks rund 3 mal schneller als normales gzip bei geringster Kopmpressionsstufe und gleich in der Stärke. Und sogar 20 mal schneller als der Rivale bzip2 bei geringster Stufe.
      Generell brauchst du die Algos nur auf geringste Stufe laufen lassen, da der unterschied in der Größe der Ausgabe nur 5-8% beträgt, die dauer aber vervielfacht.
      Wie gesagt, so musst du allerdings sehr stark darauf achten, was du so findest. Wenn du selber was machen willst, schau dir zlib.net/ an.

      MfG SDX
    • Hier gibts eine (praktisch) fertige kompressions-dll die sogar mehrere Formate unterstützt und wohl auch unabhängig vom GM läuft (kein Blockieren des Spiels während kompression).
      gmc.yoyogames.com/index.php?showtopic=292778
      Hab aber keinen Schimmer wie gut die Komprimierung selbst ist...

      Willst du auf diese Drachen und -eier klicken?
      Sie werden sich freuen ;)
    • Leider ist die DLL dafür ausgelegt, Dateien zu komprimieren, und nicht Strings. Leider liegt auch keine Source vor.
      Ich habe gerade die zlib durchstöbert und geguckt, wie machbar ein pigz Wrapper wäre. Der Code ist aber ein enttäuschendes und abschrenkendes Beispiel von unstrukturiertem code zugleich. Da schauderts mich wirklich. Schade eigentlich.

      MfG SDX
    • Es ist doch ein Leichtes den String in eine Datei zu packen und dann zu komprimieren. Hätte vieleicht zudem den Vorteil das anderes Zeug das ebenfalls zur Initialisierung benötigt werden würde, gleich mitverpackt werden könnte.
      Diese Karte muss auf dem Server ja zudem auch irgendwie als Datei vorliegen wenn sie ja dynamisch sein soll und nicht bei jedem Neustart auf Anfang gesetzt wird (sofern ich sein Vorhaben richtig verstanden habe).

      Willst du auf diese Drachen und -eier klicken?
      Sie werden sich freuen ;)
    • Diese Karte muss auf dem Server ja zudem auch irgendwie als Datei vorliegen wenn sie ja dynamisch sein soll und nicht bei jedem Neustart auf Anfang gesetzt wird (sofern ich sein Vorhaben richtig verstanden habe).

      Hm, Nein ^^ , tatsächlich wird es bei jedem serverstart auf 0 gesetzt. zumindest für den Anfang. Der server speichert genauso wie die Clients die Map in einem Grid.
      Ich werde es für den Anfang mal ohne Kompression versuchen. Mal sehen wie Lange das dauert. Das mit dem Threading der 39Dll, ist das stadartmäßig angestellt, denn ich ahb nirgends eine solche Funktion gefunden...
      EDIT:
      Werte wendelst du einfach mit ansi_char() um.

      meinst du villeicht "char()"?

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

    • Ahh, alles klar. Naja, Probieren geht wohl übers Studieren.
      Du soltest aber trotzdem irgendein Kompressionsverfahren benutzen denn wie ich grad auch festgestellt hab, reserviert die ds_grid_write Funktion eine Vielzahl von Stellen für jede Zahl. Im Idealfall kann man wie SDX erwähnt hat bei einstelligen Werten (also alle 255 ANSI-Zeichen) die Größe auf ~3% verringern im Vergleich zum Ergebnis der GM-Funktion.

      EDIT zu deinem Edit: Wie ich sehe arbeitest du grade schon dran ^^
      Viel Glück!

      EDIT2: Umh, glaube er meinte schon die Funktion

      GML-Quellcode

      1. ansi_char(val)

      Willst du auf diese Drachen und -eier klicken?
      Sie werden sich freuen ;)
    • EDIT2: Umh, glaube er meinte schon die Funktion

      GML-Quellcode

      1. ansi_char(val)

      die gibt es in meiner dokumentation nicht. :O
      die gibts bei mir generell nicht....wird nicht markiert im editor.
      Die ist neu im GM8.1 ... Irgendwas vergleichbares? was tut die funktion denn?

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

    • Ahh..
      Kann man eigentlich nicht umsonst auf 8.1 updaten?

      Glaube nicht dass es eine Ersatzfunktion gibt, aber man könnte sie vieleicht coden. Das steht in der hilfe:
      ansi_char(val) Returns a string containing the character with raw BYTE value set.

      Willst du auf diese Drachen und -eier klicken?
      Sie werden sich freuen ;)
    • Hatte hier und da mal etwas über Einschränkungen gehört, glaube das war beim Thema Creawo... Wie dem auch sei, ich versuch das jetzt mal, upgegradet und so wie zuletzt genannt.
      EDIT. So, ich hab das mal ausprobiert, und das ganze läuft nicht so wie es soll......
      Das hier, verwende ich zum Verschicken:
      var mapString , currRow , currPos;
      mapString = "";
      for (currRow = 0;currRow != 300;currRow += 1)
      {
      for (currPos = 0;currPos != 1000;currPos += 1)
      {
      mapString += ansi_char(real(string_replace(string(scrGridGet(currRow,currPos)),"-1","0")));
      }
      }
      clearbuffer();
      writestring(mapString);
      sendmessage(socket);

      und dieses zum Empfangen:
      var mapString , size , currPos , currRow;
      while(1 = 1)
      {
      size = receivemessage(global.serverSocket);
      if(size > 0)
      {
      mapString = readstring();
      for (currRow = 0;currRow != 300;currRow += 1)
      {
      for (currPos = 0;currPos != 1000;currPos += 1)
      {
      scrGridSet(currPos,currRow,real(string_replace(ord(string_char_at(mapString,(currRow * 1000) + currPos)),"0","-1")));
      }
      }
      break;
      }
      }

      Die funktionen scrGridGet und scrGridSet sind selbst geschrieben und ersetzen nur ds_grid_set und ds_grid_set. sie beinhalten schon die Grid ID und funktionieren so wie sie da sind.
      jedoch kommen nur 0en an.

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

    • DragonGamer schrieb:

      Glaube nicht dass es eine Ersatzfunktion gibt, aber man könnte sie vieleicht coden. Das steht in der hilfe:
      ansi_char(val) Returns a string containing the character with raw BYTE value set.

      Tut nicht die Funktion chr seit jeher genau das? Das Gegenstück ist, wie SDX schon erwähnt hat, ord. (ansi_char gibt's seit 8.1 und hat wohl was mit einem neuen String-Format zu tun.)

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Bl@ckSp@rk ()

    • Bl@ckSp@rk schrieb:

      DragonGamer schrieb:

      Glaube nicht dass es eine Ersatzfunktion gibt, aber man könnte sie vieleicht coden. Das steht in der hilfe:
      ansi_char(val) Returns a string containing the character with raw BYTE value set.

      Tut nicht die Funktion chr seit jeher genau das? Das Gegenstück ist, wie SDX schon erwähnt hat, ord. (ansi_char gibt's seit 8.1 und hat wohl was mit einem neuen String-Format zu tun.)

      Oh, ja, das stelle ich auch grad fest.
      ansi_char gibt das Ergebnis binär oder irgendwie ähnlich, aus. Das Ergebnis auf dem Display anzuzeigen habe ich in keinster Weise hinbekommen und geht wohl auch nicht. Was ist ein "raw BYTE value set" überhaupt? Der GM besitzt ja (noch?) keinerlei Funktionen um binäre Datenstrukturen zu bearbeiten (außer in Dateien).

      Wie auch immer. SDX meinte wohl doch die Funktion:

      GML-Quellcode

      1. chr(val)


      EDIT: Sorry, Unsinn geredet.

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

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

    • Habe mal was gehackt
      Spoiler anzeigen

      GML-Quellcode

      1. random_set_seed( 42 ); // debug
      2. var mapString , currRow , currPos, value, valueString; // valueString ist nur zum debuggen
      3. mapString = "";
      4. valueString = ""; // debug
      5. for (currRow = 0;currRow != 16;currRow += 1) {
      6. for (currPos = 0;currPos != 16;currPos += 1) {
      7. value = floor(random(255)); // hier dein Wert
      8. valueString += string(value)+" "; // debug
      9. mapString += ansi_char(value);
      10. }
      11. }
      12. show_message( "We got the following data:" ); // debug
      13. show_message( valueString ); //
      14. //
      15. show_message( "The string representation:" ); //
      16. show_message( mapString ); //
      17. show_message( "Now reverse" );
      18. var currPos , currRow, valueString, counter, value; // valueString ist nur zum debuggen
      19. valueString = "";
      20. counter = 0; // ich benutze einen counter, das darfst du aber handhaben wie du willst
      21. for (currRow = 0; currRow != 16; currRow += 1) {
      22. for (currPos = 0;currPos != 16; currPos += 1){
      23. counter+=1;
      24. value = string_byte_at(mapString,counter); // string_byte_at könnte neu sein, sollte aber das selbe wie ord(string_char_at()) sein
      25. valueString += string(value)+" "; // debug
      26. }
      27. }
      28. show_message( "We got the following data:" ); // debug
      29. show_message( valueString ); // debug
      Alles anzeigen


      Bei mir Funktioniert das nicht wenn ich Gebrauch von chr mache - es muss ansi_char sein. Soweit ich ennehmen kann, hat es was mit Unicode zu tun. Ich blicke aber selber nicht ganz durch. Vllt tut es bei älteren Versionen dann wieder - es verwirrt mich.

      MfG SDX
    • SDX schrieb:

      Bei mir Funktioniert das nicht wenn ich Gebrauch von chr mache - es muss ansi_char sein. Soweit ich ennehmen kann, hat es was mit Unicode zu tun. Ich blicke aber selber nicht ganz durch. Vllt tut es bei älteren Versionen dann wieder - es verwirrt mich.

      In der Hilfe steht ja bei chr()
      NOTE: This will change from machine to machine. If you need a specific codepage, then be sure to SET a font yourself at the start of your game..
      If the font is a sprite font, no translation will be done.

      Versuch mal vor dem Aufrufen der Funktion mit chr(), einen Font zu setzen bei dem als character-set statt "DEFAULT_CHARSET", "ANSI_CHARSET" gewählt wurde. Eventuell kann mans damit auch in der alten Version des GM's zum laufen bringen.


      EDIT: Was das angeht was ich vorhin behauptet hab dass man die Ausgabe von ansi_char nicht anzeigen kann.. beruhte auf meiner reinen Dummheit, sorry.

      EDIT2: Nein, den Font zu ändern scheint keienrlei Auswirkungen auf die Ausgabe von chr() zu haben :/

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

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

    • @SDX
      Habe deinen Code mal im GM 8.0 getestet und dort funktioniert er ohne Probleme. Hätte mich auch gewundert, wenn nicht, da ich chr und ord schon oft für diesen Zweck verwendet habe. Ich habe lediglich ansi_char durch chr ersetzt und string_byte_at(...) durch ord(string_char_at(...)).
    • Ich glaube dass mein Code von weiter oben zwar funktioniert, er aber den String nicht empfängt. Ich habe extra zum sichergehen, einen byte (16) im selben Packet mitgeschickt, um das zu überprüfen. Er öffnet das Packet, die 16 ist drinne jedoch der String leer. Kann das an der enormen Länge liegen?

      Btw war mein Spiel im GM8 um einiges Stabiler was die FPS anbelangt, als jetzt mit dem GM8.1
      Mal sehn ob ich einfach so zurück kann..

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

    • Back @ GM8:
      Ich habe jetzt einmal ein paar Tests gemacht, um herauszufinden, warum das bei mir nicht läuft. Dabei fällt mir auf, dass wenn ich in der Debug-Konsole ord(chr("2")); eingebe, er mir nicht wie erwartet "2" sondern "0" zurückgiebt. Dies passiert auch bei ord(chr("1")); und anderen Zahlen. Da wird auch klar dass es bei mir nicht klappen kann, wenn sowieso IMMER "0" heraus kommt. Woran liegt das? Habe ich da ord() und chr() falsch verwendet?
    • Partik schrieb:

      Aber haben wir nicht weiter oben gesagt, dass ich zuerst meine Werte mit chr() bzw ansi_chr() umwandle, verschicke und dann wieder mit ord() zurückwandle?
      Ja, weil du doch Zahlen hattest, oder? (Deine Map basiert ja auf Zahlen.)
      Die Darfst du der chr/ansi_char - Funktion nicht als String übergeben, sondern als Zahl.
      Wenn du schreibst

      GML-Quellcode

      1. ord(chr(2));
      kommt ebenfalls 2 raus.

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