DirectPlay Messaging  
Autor: Jack Hoxley, 07/2000 Übersetzung: Sebastian Bauersfeld, 11/2001

Ohne Zweifel kommen Internet-Spiele in den nächsten zwei Jahren groß raus (das hängt natürlich davon ab, wann du das hier gelesen hast), und als Spiel-Programmierer will man da natürlich mitmischen. Dies wird durch DirectPlay ohne große Umstände ermöglicht
 
Daten Senden

Jetzt wird es interessant, die Grund-Idee von DirectPlay ist, Informationen zwischen zwei Computern in Form von Nachrichten auszutauschen. Es gibt zwei Arten von Nachrichten, System-Nachrichten (automatisch) und benutzer-definierte Nachrichten (ausgelöst von Spielern). Eine typische Systemnachricht ist z.B. "Spieler XX ist dem Spiel beigetreten!" oder "Das Spiel wurde beendet". Eine typisch benutzerdefinierte Nachricht kann eine Chat-Nachricht (die der User sieht) oder ein Update-Paket (vom Programm gesendet) sein, dass z.B. Spieler X mitteilt, dass sich Spieler Y bewegt hat - was dann auch auf dem Bildschirm sichtbar wird.

Wenn man Nachrichten sendet, sollte man diese möglichst klein halten. Es ist klar, dass große Nachrichten alles verlangsamen (denn der Empfänger muss sie ja auch schnell downloaden). Eine hohe Wartezeit (Latency, Ping/Lag) ist die Folge davon, wenn man viele Daten verschickt - jeder Online-Spieler wird dir sagen, dass das nicht gut fürs Spiel ist. Es gibt drei Sachen, die man beachten sollte, wenn man Pakete (Nachrichten) sendet:

1. 

Kompression. Dieses Thema fordert viel Testarbeit. Aber bevor man große Datenmengen verschickt, sollte man versuchen, sie erst mal zu komprimieren. Man sollte dabei aber beachten, dass der Empfänger diese Daten erst wieder dekomprimieren muss, bevor er diese nutzen kann.

2

Zeiteinteilung. Viele Leute beachten das nicht, aber es steigert die Geschwindigkeit des Programms enorm. Viele machen den Fehler, ein Datenpaket in jedem Schleifendurchlauf zu verschicken, wenn man einen schlechten Ping hat, dann wird dieser dadurch nur noch verschlechtert. Zeiteinteilung heißt z.B., dass man Daten nur bei jeden 2., 3. oder 4. Schleifendurchlauf verschickt. Bei einen guten PC würde das ausreichen, mit einem schlechterem hat man da aber schon so seine Probleme. Hier wäre es vielleicht besser, Datenpakete nur alle 100ms (10x pro Sekunde) zu verschicken. Man kann in diesen Dingen auch den User entscheiden lassen. Er wird schon wissen, wie gut seine Verbindung ist. Er nimmt vielleicht weniger flüssige Bewegungen für ein bisschen schnelleres Spielen in Kauf.

3

So wenig wie möglich senden. Man sollte nichts in das Datenpaket packen was man auch nicht braucht. Wenn man eine neue X, Y, Z-Koordinate für einen Spieler sendet, sollte man sie nicht in der Form "X = 90  Y = 12  Z = 0.1" (15 Byte) sondern in der Form "90|12|0.1" (9 Byte) senden. Somit hat man 6 Bytes gespart. Vorzugsweise kann man diese Informationen als Binärzahlen verschicken. Das scheinen alles nur winzige Kleinigkeiten zu sein, allerdings können sie großen Einfluss auf das Spiel haben.

Nun möchten wir eine Nachricht senden

Selbstverständlich muss man zwei Dinge beim Senden einer Nachricht angeben: die Quelle und das Ziel. Als Erstes werden wir lernen, wie man eine Nachricht beschreibt. Dafür gibt es einen eingebauten Datentypen, die DirectPlayMessage. Diese füllen wir mit Informationen und verschicken sie.

Definieren wir ein paar Konstanten, die die Art der Nachricht angeben, das ist wichtig, da der Zielcomputer somit weiß welche Art von Nachricht er bekommen hat (entweder er bekommt eine Chat-Nachricht oder er empfängt wichtige Daten für das Spiel)

const MyGame_ChatMessage = 0
const MyGame_DataPacket = 1
const MyGame_SomeOtherType = 2
const MyGame_YetAnotherMessageType = 3

  'Dieses Objekt beinhaltet alles was wir zum Senden brauchen.
Dim Msg As DirectPlayMessage

  'Wir benutzen DirectPlay zum initialisieren unseres
  'Nachrichten-Objektes.

Set Msg = Dp.CreateMessage

  'Die Nachricht erhält unsere IdentifikationsKonstante.
Msg.WriteLong MyGame_ChatMessage

  'Nun fügen wir der Nachricht einen String hinzu
Msg.WriteString "Hallo. Ich bin ein Chat-String." 

  'Es gibt einige verschiedene Datentypen die man in die Nachricht
  'hineinschreiben kann:
    'WriteSingle = Daten vom Typ Single
    'WriteDouble = Daten vom Typ Double
    'WriteShort = Daten vom Typ Integer
    'WriteLong = Daten vom Typ Long
    'WriteGUID = Daten vom Typ String
    'WriteString = Daten vom Typ String
    'WriteByte = Daten vom Typ Byte

  'Nun haben wir die Nachricht mit allen wichtigen Daten gefüllt und
  'können sie zu einem oder 'mehreren Spielern senden


dp.SendEx PlayerID, DPID_ALLPLAYERS, DPSEND_GUARANTEED, Msg, 0, 0, 0
Nun müssen wir erst mal ein paar Parameter von diesem Aufruf erklären:
Der erste Parameter ist die Spieler-ID des lokalen Computers. Diese ID wird zurückgegeben wenn man einen Spieler erstellt.
Der Zweite gibt an wer die Nachricht bekommen soll (entweder man gibt die spezifische ID für einen Spieler an, oder man schickt die Nachricht mit DPID_ALLPLAYERS an alle Mitspieler)
Der dritte Parameter beschreibt wie die Nachricht gesendet werden soll, hier ein paar Beispiele:
DPSEND_ASYNC

Das Programm versucht solange die Nachricht zu senden bis dieser Versuch erfolgreich war

DPSEND_ENCRYPTED

Entschlüsselt die Nachricht; ist nur in einer gesicherten Session möglich

DPSEND_NOSENDCOMPLETEMSG

Funktioniert nur wenn ASYNC auch benutzt wird.

DPSEND_SIGNED

Wenn möglich sollte man eine digitale Signatur benutzen. Funktioniert nur zusammen mit dem GUARANTEED flag.

GUARANTEED

Das Programm versucht solange die Nachricht zu senden bis diese beim Empfänger angekommen ist.

Der vierte Parameter definiert den Prioritätslevel; nicht jeder Server / jede Verbindung unterstützt diese Option, darum sollte man darauf achten ob ein DPERR_UNSUPPORTED erscheint. Die Wichtigkeit der Nachricht kann eine Zahl zwischen 0 und 65536 sein, und wird nur gesendet, wenn es keine anderen Nachrichten mehr gibt die eine höhere Priorität haben.

Der fünfte Parameter gibt das TimeOut in ms an. Wenn eine Nachricht nicht innerhalb der angegebenen Zeit gesendet werden kann, wird sie gelöscht. Das ist nützlich wenn die Nachricht nur zu einen bestimmten Zeitpunkt wichtig ist. Wenn die Zeit auf 0 gesetzt wird, gibt es kein Zeitlimit. Diese Eigenschaft unterstützen auch nicht alle Server.

Der letzte Parameter kann meistens ignoriert werden. Er ist nur von Bedeutung für die Nachrichten- ID.

So, nun bist du in der Lage eine Nachricht zu einem anderen Spieler zu senden. Du musst nur gut überlegen welche Nachrichten -Parameter ( Flags) du benutzt, da sich das stark auf dein Programm auswirkt. z.B. brauchen nur Chat-Nachrichten den GUARANTEED-Flag, damit man auch sicher gehen kann, dass die Nachricht beim Empfänger angekommen ist.

Ein Datenpaket (das z.B. mitteilt, dass sich irgendein Objekt bewegt hat) braucht den GUARANTEED-Flag nicht. Anstelle dessen kann man den ASYNC-Flag benutzen, da sich das Objekt ja sicherlich kontinuierlich bewegt (und somit mehre Nachrichten hintereinander gesendet werden müssen). Dadurch sind vorhergehende Nachrichten schon wieder veraltet.
 
Nun haben wir etwas gesendet und wollen jetzt etwas empfangen.

Es macht keinen Sinn Nachrichten zu senden, wenn man sie nicht empfangen kann. Also müssen wir unseren Code nun an die Ansprüche der Nachrichten anpassen. Wenn man erst mal alle Daten von DirectPlay empfangen hat, kann man damit machen was man will. Dabei sollte man aber beachten, dass man die Daten in derselben Reihenfolge aus der Nachricht auslesen muss, wie man sie dort hineingeschrieben hat.

  'Nun brauchen wir erst mal ein paar Variablen...
Dim FromThisPlayer As Long
Dim ToThisPlayer As Long
Dim
NumMessagesWaiting As Long
Dim MsgType As Long
Dim Msg As DirectPlayMessage

  'Die Anzahl der anstehenden Nachrichten für unseren Spieler
  'herausfinden.

NumMessagesWaiting = Dp.GetMessageCount(PlayerID) 

Do While NumMessagesWaiting > 0
  Set Msg = Dp.Recieve(FromThisPlayer, ToThisPlayer, DPRECIEVE_ALL)

   'Die Variablen FromThisPlayer und ToThisPlayer haben die ID's
   'der zu ihnen passenden Spieler.
   'DPRECIEVE_ALL heißt grundsätzlich das wir nach allen
   'Nachrichten gucken. Nun können wir alle Daten entpacken.


  MsgType = Msg.ReadLong()

   'Nun bearbeiten wir die Nachricht - das werden wir in einer
   'anderen Prozedur tun.

  ProcessMessage MsgType, FromThisPlayer

   'Nun verringern wir die Anzahl der wartenden Nachrichten,
   'weil wir ja gerade eine Nachricht gelesen haben.

  NumMessagesWaiting = NumMessagesWaiting -1
Loop

Sub ProcessMessage(Type As Long, From As Long)
  If From = DPID_SYSMSG then
    'Wir haben eine Nachricht von DirectPlay erhalten. Es gibt
    'eine Menge System-Nachrichten; die wichtigsten sind:

    'DPSYS _CREATEPLAYERORGROUP - Ein neuer Spieler oder eine neue
            'Gruppe sind beigetreten
    'DPSYS _DESTROYPLAYERORGROUP - Ein existierender Spieler
            'verlässt das Spiel
    'DPSYS_HOST - Der Host verlässt das Spiel, die Applikation die
            'diese Nachricht empfängt ist nun der neue Host.
    'DPSYS _SESSIONLOST - Die Verbindung mit der Session wurde
            'verloren.

  Else

      'Wir haben eine benutzerdefinierte Nachricht erhalten. Wir
      'sollten Select Case benutzen:

    Select Case Type
      Case MyGame_ChatMessage

        'Hier kommt der Code hinein, der eine Chat-Nachricht
        'entpackt und auf dem Bildschirm abbildet

      Case MyGame_DataPacket

        'Hier kommt der Code hinein, der ein Datenpaket entpackt
        'und verarbeitet.

    End Select
     'Du solltest weitere Cases für die Konstanten die wir oben
     'deklariert haben, einfügen.

  End If
End Sub
Nun solltest du in der Lage sein, Nachrichten für deine Anwendung zu senden und zu empfangen. Einen ziemlich großen Teil von DirectPlay haben wir schon geschafft. Das schlimmste hast du also hinter dir.
Einen Beispiel-Chat können Sie hier downloaden.
  Download BitmapBlt.zip Download
tip0185.zip
 (13,3 kB)
Downloadzeit: <1 Min. - 28.8k / <1 Min. - ISDN Downloads bisher: [ 2460 ]

Startseite | VB-/VBA-Tipps | Projekte | Tutorials | API-Referenz | Komponenten | Bücherecke | Gewinnspiele | VB-/VBA-Forum | DirectX-Forum | VB.Net | .Net-Forum | Foren-Archiv | Chat | Spielplatz | Links | Suchen | Stichwortverzeichnis | Feedback | Impressum

Seite empfehlen Bug-Report

Letzte Aktualisierung: Mittwoch, 15. Mai 2002