Mplay in Studio

    • Game Maker

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

    • Heute gibt es ein Paar aktuelle News hierzu:
      yoyogames.com/tech_blog/11


      Übersetzung noch in Arbeit:
      Spoiler anzeigen


      In dieser aktuellen Version von GameMaker: Studio, haben wir einige experementelle Netzwerkfunktionen hinzugefügt. Hiermit werde ich euch einen kleinen Überblick verschaffen wie das Ganze funktioniert, was die wichtigsten Regeln sind und einen Weg zeigen, wie man einen simplen Client/Server im Spiel benutzt. Das ganze wird auf dem neuen "Networked Plattformer" Example basieren, also solltest du kurz durchstöbern um sich eine grobe Vorstellung zu verschaffen.

      Zuallererst, das Netzwerksystem basiert auf "Sockets"; diese sind Werksstandart und auf allen Plattformen, jedoch noch momentan ausschließend HTML5, vertreten.

      Wir geben dir die Möglichkeit, Clients und Server in GML so zu erstellen, dass du auch Singleplayer Games über ein Client / Server-Modell erstellen kannst - das ermöglicht ins Spiel Multiplayer später einzufügen. Auf die Sockets werde ich nicht lange eingehen, das ist ein umfangreiches Thema mit vielen Tutorials, Demos und Beschreibungen im Netz, aber ich werde einen kurzen Überblick, was ein Socket ist verschaffen.

      Ein Socket ist ein Objekt welches senden, empfangen, verbinden und abfragen von Ports im Netzwerk möglich macht. Zunächst werden wir mit nur TCP / IP-Verbindungen, auf welchen das Intertnet selbst basiert (IPv4 um genauer zu sein) arbeiten


      Diese im Grunde können Sie verbinden eine Steckdose mit einer IP-Adresse (sagen wir 192.168.1.10) zu einem anderen Socket auf einem anderen IP-Adresse (zB 192.168.1.11). Einmal verbunden, können sie zwei Buchsen Daten hin und her zu senden mit dem network_send_packet ()-Funktion und die Netzwerk ASYNC Event - aber wir werden in später. Erstens, IP-Adressen haben auch was ist angelaufenen Häfen. Anstelle von Programmen aufweist, zu lesen und bei jedem Bit der Netzwerkverkehr in eine Maschine umzugehen, IP-Adressen auch mit Ports umgehen, im Bereich von 0 bis 65535. Dies ermöglicht jedem Programm, um nur die Pakete, die es in ist interessiert, und nicht alles zu bekommen - dies spart auch erhebliche CPU-Zeit, als es schneidet ernsthaft sich auf Datenverarbeitung. Eine Sache, die Sie beachten sollten, ist, dass einige Ports bereits im Einsatz sind von Ihrem sysem, und so sollten Sie versuchen, eine "höhere" Port-Nummer zu wählen. Sie können eine Liste von ihnen hier zu sehen.

      Um das Leben ein wenig leichter zu machen, können Sie auch "zuhören" Ports. So ein Server wird eine Steckdose, und dann binden Sie es an einem bestimmten Port zu hören. Es wird dann von Verbindungen, Trennungen und Datenübertragungen benachrichtigt.

      So ... schnelle Überprüfung einer Steckdose, können Sie mit einem Port auf eine IP-Adresse zu verbinden, und lesen / schreiben einige Daten, während ein Server "hören" kann zu einem Hafen, und dann bekommen Verbindung / Trennung Info und lesen / schreiben einige Daten . So erstellen Sie einen Server, so sage es an einem Port zu hören, und wenn ein Client versucht, eine Verbindung, die Server-Mitteilungen, verbindet und erzeugt dann ein "Bindeglied" zwischen ihnen, so dass sie sich frei zu senden Daten hin und her. Ziemlich geradlinig so weit.

      Nun geschieht das alles asynchron. Das heißt, Sie senden Daten aus, haben aber keine Ahnung, wenn Daten kommen in. Um dabei zu helfen, haben wir ein neues Netzwerk ASYNC Ereignis aufgenommen. Alle Daten werden durch dieses Ereignis erhielt, zusammen mit allen verbinden / trennen Details.

      Das heißt, wir können überall senden, aber alle eingehenden Daten geschieht durch die Veranstaltung - sowohl für Client und Server. Das heißt, wir müssen wissen, wer die Daten für ist, und was es enthält. Jetzt Buchsen sind "Streams", und das bedeutet, wenn eine Maschine zu senden zwei Datenpakete auf einen Server, kann es am Ende immer ein großer Block von Daten in den Rückruf. Also anstatt zwei Rückrufe von 32 Bytes, erhalten Sie einen Rückruf von 64 Bytes. Das macht das Leben ein wenig knifflig. GameMaker können dabei helfen. Die network_send_packet ()-Aufruf wird automatisch aufgeteilt diese bündelt - Sie müssen nicht, aber ich würde es empfehlen. GameMaker befestigt eine kleine Überschrift zu jedem Paket gesendet, sodass es weiß, dass es ein Paket, und die Größe und damit erlaubt es, jeden einzelnen zu verarbeiten, die Handhabung des störenden Stroms für Sie.

      Also, was Sie jetzt am Ende mit, ist ein Rückruf für jedes Paket eine Client, den Sie gesendet wurde. Dies lässt Sie frei, um die Server-Code auf einfache Datenpakete basieren schreiben.

      So genau, wie sollten Sie schreiben eine einfache vernetzten Spiel? Nun, es ist offensichtlich eine unendliche Zahl von Möglichkeiten, so dass wir eine sehr einfache (und bei weitem nicht perfekt!) Beispiel nehmen und zu diskutieren, dass. Für unser System, wir das ganze Spiel auf dem Server ausgeführt, so dass der Kunde nur die Ergebnisse anzeigen.

      Now normally in a single player game, you’d have a simple player object running around and checking for keys itself, but for our networked game, we’re going to change that. Rather than the keyboard being directly checked by the player, we’ll create a new oClient object that checks keys, and it will then forward these key pressed/released events to the server as they happen. This is very light on network traffic as, if you are running right (say), you get one event to start running, and then much later, one to stop. Only 2 network packets in total, which is ideal.

      So, next we’ll need a server, something that will receive these keys and process all the connected players somehow. On creation, our oServer object attempts to create a socket and then attempts to listen to port 6510, waiting for a client to connect (see below). The “32” is the total number of clients we want to allow to connect at once. This number is up to you, too many, and your game will saturate the network or your CPU won’t be able to handle the processing of that number of players – use with care.

      server = network_create_server( network_socket_tcp, 6510, 32 );
      If this fails, then we may already have a server on this machine – or the port is in use by another program. Only one socket can listen to the same port at once, so if something else is using it, you’ll need to pick another. Once our server is created and listening, we can then get our client to connect.

      First, we’ll deal with a creating a socket, and connecting.

      client = network_create_socket( network_socket_tcp );
      network_connect( client, “127.0.0.1”, 6510 );
      “127.0.0.1” is a special network address that is ONLY your machine. It’s a “loopback”, meaning nothing actually goes out on the network, but delivered directly back to your own machine. This can be changed later.

      And that’s it! Once connected, we are now ready to send data back and forth from client to server! The first thing the client does is to send a special packet to the server, telling it the players name. To do this we use one of our new “binary buffers” (please see the manual for details) This lets us create a packet of raw, binary data that we can send to the server. Buffers are pretty simple to use. Simply create one, write some data, and then send it. I would recommend you keep the buffer around so that you can reuse it, remembering that if you do you’ll, need to reset the read/write head back to the start each time. So inside our oClient object, we’ll create a new buffer

      buff = buffer_create( 256, buffer_grow, 1)
      This creates a new buffer 256 bytes in size, that will grow as needed, with an alignment of 1 (no spaces left), which for our minimal traffic, is just fine.

      To send some data to the server we simply have to write it to the buffer, and send it.

      buffer_seek(buff, buffer_seek_start, 0);
      buffer_write(buff, buffer_s16, PING_CMD );
      network_send_packet( client, buff, buffer_tell(buff) );
      And that’s it. The buffer_seek() at the start allows us to reuse the buffer as the networking system always takes the data from index 0 in the buffer, and throwing buffers away every time is a waste.

      So, how does the server get this data? Well using the new Network event, it’s pretty straight forward as well.



      We simply pick the networking event from the menu (shown above), and then we can start writing some client/server code for when the data arrives (as shown below).



      The network event creates a new ds_map and assigns async_load to hold it, and this allows us to look up everything we need, and this lets us decide on the current course of action.

      var eventid = ds_map_find( async_load, “id” );
      This returns the socket ID that threw the event. This can either be the server ID, or an attached client ID. If it’s the server ID then we have a special connection/disconnection event, and it’s at this point we can start creating new players for the attaching client, or throwing them away if they disconnect.

      So, to tell if it’s a connection or a disconnection, we’ll check the “type” in the ds_map.

      var t = ds_map_find_value(async_load, "type");
      If t==1, then it’s a connection, and so we can get the new socket ID and IP it’s come from.

      var sock = ds_map_find_value(async_load, "socket");
      var ip = ds_map_find_value(async_load, "ip");
      The variable sock will hold the ID that has been assigned to that client, and this will be the same as long as the client stays connected. We can therefore use this as a lookup for any client data.

      The simplest way of getting client info, is to use a ds_map and use sock as a lookup to an instance which can hold all the clients variables/data. So all you need to do is create a “clients” ds_map in the create event of oServer, and then on connection, the server will create a new player, and add it to a ds_map like this…

      var inst = instance_create( 64,192, oPlayer );
      ds_map_add( clients, sock, inst );
      This then means that whenever some incoming data arrives from the client, we can simply lookup the instance and then assign the data as needed. If it was 0, then we simply have to remove the socket from the map, and delete the player instance.

      So the next thing to tackle, is what happens when the client sends some data to the server. This comes in to the Network Event with a sock ID that isn’t the server’s, but one we’ve already connected and initialised. This means all we need to do in the server network event code, is check it’s not the server socket, and if it’s not… lookup the instance in the ds_map, start reading the data into there.

      var buff = ds_map_find_value(async_load, "buffer");
      var sock = ds_map_find_value(async_load, "id");
      var inst = ds_map_find_value(Clients, sock );
      So this now gives us the buffer where the client data is, the socket ID it came in from, and the instance attached to that socket; everything we need to read the data and process it. We can now read the data from the buffer, and then store the relevant information in the instance.

      The last part of this puzzle is sending out updates to the client, and having it display the game. This is again, pretty simple and handled through a Network Event, and the only difference is that we want to buffer the information coming in, in case there is a connection issue. In the case of our little example, what it does is to simply draw all the sprites sent to it by the server. The server “step” event does this every frame, for all the attached players and active baddies, this keeps it simple for the example.

      It should be noted that this is where “smart” client/server models differ from what we have here. They will try to minimise the data being sent, sending out single updates, and limiting how often it transmits. We don’t do anything like that. This system will work fine for a game on a local network, with a few players, but will probably break instantly if you tried this over the internet. Still, with this in mind, how does our simple client receive the data?

      First we’d add a network event as we did the server, and then the first thing we’ll check, is that the event ID is the client id – if it is, then it’s for us.

      var eventid = ds_map_find_value(async_load, "id");
      if( client == eventid )
      {
      }
      Now, to buffer the incoming data I opted to use a ds_list, I simply create this in the oClient create event, and then whenever we get new data, we clear it, and add the data to it. Simple.

      var buff = ds_map_find_value(async_load, "buffer");
      sprites = buffer_read(buff, buffer_u32 ); // Number of sprites

      ds_list_clear(allsprites);
      for(var i=0;i<sprites;i++){
      ds_list_add(allsprites, buffer_read(buff,buffer_s16) ); //x
      ds_list_add(allsprites, buffer_read(buff,buffer_s16) ); //y
      ds_list_add(allsprites, buffer_read(buff,buffer_s16) ); //sprite_index
      ds_list_add(allsprites, buffer_read(buff,buffer_s16) ); //image_index
      ds_list_add(allsprites, buffer_read(buff,buffer_s32) ); //image_blend
      ds_list_add(allsprites, buffer_read(buff,buffer_string) ); // player name
      }
      Now that we have something to draw, we can draw this inside the oClient’s draw event in a simple loop.

      var index = 0;
      for(i=0;i<sprites;i++){
      var xx,yy,sp,spindex, col;
      xx = ds_list_find_value(allsprites,index++);
      yy = ds_list_find_value(allsprites,index++);
      sp = ds_list_find_value(allsprites,index++);
      spindex = ds_list_find_value(allsprites,index++);
      col = ds_list_find_value(allsprites,index++);
      name = ds_list_find_value(allsprites,index++);

      draw_sprite_ext(sp,spindex,xx,yy,1,1,0,col,1.0);
      }


      And that’s it really…. So, let’s quickly recap. We have oClient, oServer and oPlayer.


      The oClient is a dumb client that sends key presses to the server, and will draw all the sprites the server sends back.


      oServer is the controller; it will connect/disconnect clients, create new players as they come in (and map them to a socket id), and send out all sprites to all connected clients.


      oPlayer is just like it was in a single player game (in this case), except it no longer checks keys directly, but an array of keys the server fills in when it gets key presses from the client.
    • Und für Tice zur abkühlung:
      twitter.com/mdf200/status/304162635228782592


      Es wird wieder möglich sein mehrere Clients parallel laufen zu lassen, wenn ich dein Problem richtig verstanden habe.

      @ MewX: lassen wir uns überraschen, Update wurde ja immerhin für diese Woche angekündigt, daraus können wir bestimmt mehr Informationen entnehmen.
    • Sorry, habe irgendwie den ersten Satz überlesen. Viel einfacher wird es aber leider nicht.

      Du musst dir erstmal vor Augen führen, dass die Spiele nichts voneinander wissen, aber sich gegenseitig Nachrichten schicken können. Anhand dieser Nachrichten müssen sie die korrekte Spielsituation rekonstruieren. Dabei sollte man darauf achten, dass jederzeit eine Nachricht verloren gehen kann oder ein Teilnehmer ausfällt.
      Dann musst du auch entscheiden, welche Arbeit du vom Server und welche vom Client erledigen lässt. Letzteres geschieht natürlich auch auf Vertrauensbasis - wenn du dem Client die Verantwortung über die Bewegung der Spielfigur überlässt und nur die Positionen an den Server überträgst, wären Speedhacks und Wallhacks möglich. Sendest du aber nur die Tastendrücke an den Server, hast du einen großen Teil der Last auf dem Server und die Spielfigur reagiert nur sehr verzögert.

      Als ich damals noch WoW gespielt habe, sah das im Grunde so aus:

      Client:
      - Bewegt Spieler, überprüft Kollisionen
      - Überprüft Cooldowns (ob Fähigkeiten bereit sind)
      - Überprüft Sichtlinie
      - Sendet eigene Position und derzeitige Bewegung (Stehen/Gehen/Richtung)
      - Sendet Wunsch, Angriff auszuführen, falls Bedigungen erfüllt sind

      Server:
      - Bewegt Spieler an erhaltene Position, schätzt weitere Bewegungen anhand übermittelter Richtung ab (so sieht das Laufen flüssig aus)
      - Überprüft nochmal Cooldown und Sichtlinie
      - Sendet andere Spielerpositionen und sonstiges Feedback (Angriffe etc.)


      Wie du sehen kannst, werden soviele Überprüfungen wie möglich beim Client schon einmal gemacht, damit der Traffic gering bleibt. Das sollte als Einstieg erstmal reichen...
    • wie kann man die lan function benutzen,
      denn so kann ich nichts mit multiplayer anfangen :huh:
      Ein Bug ist mehr als nur ein Bug, es ist ein... Käfer!
      Egal, wie gut du eine Mauer baust, sie fällt um.... der klügere gibt nach :D

      Willst du mit mir auf Discord Chatten/Quatschen?
      Meine Husi's Tutorial Reihe
    • und warum sagen die dann das es neuerdings so etwas gibt ?
      in den kostenden versionen gab es das doch schon lange, oder?
      Ein Bug ist mehr als nur ein Bug, es ist ein... Käfer!
      Egal, wie gut du eine Mauer baust, sie fällt um.... der klügere gibt nach :D

      Willst du mit mir auf Discord Chatten/Quatschen?
      Meine Husi's Tutorial Reihe
    • husi012 schrieb:


      und warum sagen die dann das es neuerdings so etwas gibt ?


      Es ist jetzt neu dazu gekommen.

      husi012 schrieb:


      in den kostenden versionen gab es das doch schon lange, oder?


      Nein, da ging es nur mit 39dll.
      Kopiere dies in deine Signatur, um es in deiner Signatur zu haben.
      Achtung: Dieser Beitrag läuft ende des Monats ab, bitte lese ihn noch vor dem Monatswechsel...
      Nach langer zeit wieder im Forum aktiv :D
    • und so mit pro oder irgend eine andere version kann das dann auch mit 39dll?
      eine frage noch :
      wie benutzt man dlls
      Ein Bug ist mehr als nur ein Bug, es ist ein... Käfer!
      Egal, wie gut du eine Mauer baust, sie fällt um.... der klügere gibt nach :D

      Willst du mit mir auf Discord Chatten/Quatschen?
      Meine Husi's Tutorial Reihe
    • Nein, da ging es nur mit 39dll.
      Der Game Maker hatte schon vorher eingebaute Multiplayer - Funktionen, eben diese "mplay" Funktionen. Diese wurden aber beim Game Maker Studio entfernt, weil diese nicht auf allen Plattformen funktionierte (mplay war DirectX, und das gibt es nur auf Windows).

      wie benutzt man dlls
      Suche benutzen.
      wupto.net/ Nicht meine Seite!
      We love Koalas.

      GM-D-Spam-o-Meter: 32%