eMail
 Suche
 Impressum

Subsections


6. Verwendung des Frameworks

Um die Verwendung der im vorherigen Kapitel beschriebenen Implementierung des Frameworks zu demonstrieren und um eine laufende Anwendung zu testen wurden einige Beispiele und kleine Programme geschrieben.

6.1 Einfache Tools

Zunächst werden einige einfache Tools vorgestellt, welche einzelne Funktionen erfüllen. Diese Tools sind eigenständig lauffähig und sollten auch mit jeder Implementierung des Frameworks funktionieren.

Die nachfolgenden Beispiele sind im Package de.tud.dvs1.utils.* zu finden.

6.1.1 PingServer

Das Tool ``PingServer'' verbindet sich kurz mit einem MMPGP2P-Server und beendet sich dann wieder. Bei erfolgreicher Verbindung wird die auf dem Server laufende Version ausgegeben.

Das Programm kennt folgende (optionale) Parameter:

  • $--$verbose: Zusätzliche Informationen ausgeben.
  • $--$server: Standardmäßig wird zum fest einkompilierten MMPGP2P-Server verbunden. Mit diesem Parameter kann man einen beliebigen Server anpingen.
  • $--$port: Falls der MMPGP2P-Server nicht auf dem Standard-Port läuft, kann man mit diesem Parameter den richtigen Wert übergeben.

Beispiel:
Pingt den Server auf localhost:11222 an.
java de.tud.dvs1.utils.PingServer $--$verbose $--$server localhost $--$port 11222


6.1.2 SendCommand

Dieses Tool kann einen MmpgP2PCommand (siehe 5.5.1) an einem RegionController senden.

Das Programm kennt folgende (optionale) Parameter:

  • $--$verbose: Zusätzliche Informationen ausgeben.
  • $--$rc: Standardmäßig wird der RegionController des fest einkompilierten MMPGP2P-Server kontaktiert. Mit diesem Parameter kann man einen beliebigen RegionController anpingen.
  • $--$port: Falls ein RegionController nicht auf dem Standard-Port läuft, kann man mit diesem Parameter den richtigen Wert übergeben.
  • $--$command nr: Mit diesem Parameter kann man die ID des Kommandos angeben.
  • $--$args arg1 arg2 ...: Falls dieser Parameter benutzt wird, dann muss er zuletzt angegeben werden. Die nachfolgenden Argumente werden nämlich als Array von String-Argumenten an den Server übertragen.

Beispiel:
Sende Kommando Nr. 1500 mit Argumenten ``move 10 10'' an den RegionController auf localhost:11555.
java de.tud.dvs1.utils.SendCommand $--$verbose $--$rc localhost $--$port 11555 $--$command 1500 $--$args move 10 10

Das Programm kann jedoch keine komplexen Kommandos erzeugen, nur solche mit Strings als Parameter.


6.1.3 StandaloneRC

Normalerweise wird ein RegionControllerThread beim Starten eines Clients automatisch ausgeführt. Zu Testzwecken benötigt man manchmal weitere RegionControllerThreads, die man mit diesem Programm starten kann.

Das Programm kennt folgende (optionale) Parameter:

  • $--$rcdebug: Debugging im RegionControllerThread aktivieren.
  • $--$rchost: Gibt einen Hostnamen an, mit welchem sich der RC beim Server meldet.
  • $--$rcport: Steuert den Port, auf dem der RegionController lauschen soll.
  • $--$server: Gibt den Hostnamen des Server an, zu dem sich der RC verbinden und als frei melden soll.
  • $--$serverport: Gibt den Port an, auf dem der Server läuft.

Beispiel:
Starten eines RegionControllerThread auf Port 12345 und verbindet sich mit Server ``freedom'' auf dem standart Serverport:
java de.tud.dvs1.utils.StandaloneRC $--$rcport 12345 $--$server freedom

6.1.4 SendGameWorld

Dieses Programm erzeugt eine Spielewelt mit einigen zufällig generierten Objekten und sendet diese an einen RegionController.

Das Programm kennt folgende (optionale) Parameter:

  • $--$verbose: Zusätzliche Informationen ausgeben.
  • $--$rc: Standardmäßig wird der RegionController des fest einkompilierten MMPGP2P-Server kontaktiert. Mit diesem Parameter kann man einen beliebigen RegionController kontaktieren.
  • $--$rcport: Falls ein RegionController nicht auf dem Standard-Port läuft, kann man mit diesem Parameter den richtigen Wert übergeben.

Dieses Programm könnte man erweitern, um diverse Spielwelten zu testen oder eine Art Kartenrotation zu implementieren.


6.1.5 BotPlayer

Die Klasse BotPlayer ist eine einfache Implementierung des ClientThreads, ähnlich der später in Abschnitt 6.6 erwähnten Implementierung. Diese Klasse simuliert einen Client, der seinen Avatar durch die Welt bewegt und Gelegentlich auf Objekte feuert. Achtung: die Verwendung dieses Bots ist nur sinnvoll im Zusammenhang mit der Beispiel-Implementierung.

Das Programm kennt folgende (optionale) Parameter:

  • $--$nr: Gibt an, wieviel BotPlayer innerhalb dieses Aufrufes gestartet werden.
  • $--$interval: Nur im Zusammenhang mit $--$nr sinnvoll. Gibt die Wartezeit zwischen zwei startenden BotPlayern an.
  • $--$norc: Mit diesem Parameter kann man das Starten eines RCs verhindern.
  • $--$rcdebug: Zusätzliche Informationen des RegionControllers ausgeben.
  • $--$rcport: Falls der zu startende RegionController nicht auf dem
  • $--$rcport: Falls der zu startende RegionController nicht auf dem
  • $--$server: Gibt den Hostnamen des Server an
  • $--$serverport: Gibt den Port an, auf dem der Server läuft.
  • $--$noaction: Der Bot loggt sich ein, beginnt das Spiel, führt dann aber keinerlei Spielzüge durch.


6.2 Tutorial zur Verwenden des Frameworks

Um die Funktionsweise des vorgestellten Frameworks zu demonstrieren, wurde ein einfaches Spiel entwickelt. Der Ablauf des Spiels ist sehr einfach gehalten, ebenso die grafische Oberfläche. Jedoch sollte es die grundsätzlichen Möglichkeiten des Systems zeigen können.

Die zugehörigen Klassen sind im Package de.tud.dvs1.example zu finden. Im Folgendem wird genau beschrieben, wie man das Framework für die Entwicklung eines Spiels einsetzt. Für jeden Schritt wird jeweils ein Beispiel aufgeführt.

Die Implementierung gliedert sich in folgende Schritte. Im den nachfolgenden Abschnitten werden diese Schritte jeweils detailliert erklärt.

  1. Avatar implementieren (siehe Abschnitt 6.3)
  2. Ruleset implementieren (siehe Abschnitt 6.4)
  3. ServerThread implementieren (siehe Abschnitt 6.5)
  4. ClientThread implementieren (siehe Abschnitt 6.6)

Die Hauptarbeit beim Verwenden des Frameworks sollte das Implementieren des Ruleset machen, denn hier wird die komplette Spielelogik modelliert.


6.3 Ruleset implementieren

Das Ruleset bestimmt die Spielregeln. Die RegionController führen ihre Berechnungen des Weltzustandes regelmäßig über Funktionen aus, die das Ruleset zur Verfügung stellt. Die Implementierung muß einige Methoden implementieren, in denen sie Objekt-Manipulationen durchführt.

Für eine systemkomforme Benutzung des Rulesets sind in Kapitel 5.3.1 einige Regeln aufgezählt, an die sich die Implementierung halten muß.

6.3.1 Implementierung der abstrakten Methoden

Die Beispielimplementierung kennt ein FIRETO und ein MOVETO Kommando, welche von den Clients übermittelt werden und in der Methode applyCommand() implementiert sind.

  • targetReached()
    In dieser Methode wird eine Besonderheit des Spieltyps der Implementierung umgesetzt. Ist ein Objekt vom Typ CANNONBALL an seinem Ziel angekommen, dann ``explodiert'' das Geschoß dort und zieht nahe Objekte in Mitleidenschaft. Die ``geschädigten'' Objekte werden manipuliert und als Array zurückgeliefert. Das CANNONBALL-Objekt wird aus der Welt entfernt.
    Falls ein sonstiges Objekt sein Ziel erreicht, wird zufällig ein neues Ziel gewählt, dass sich innerhalb der Grenzen der aktuellen Teilwelt befinden. Bewegliche Objekte bleiben also weiterhin in Bewegung.
  • applyCommand()
    An dieser Stelle werden das FIRETO und MOVETO Kommando ausgeführt.
       
      public static final int MOVETO = 2000;
      public static final int FIRETO = 3000;
    
      public GameObject[] applyCommand(GameWorld world, MmpgP2PCommand c) 
        throws MmpgP2PException 
      {
        switch (c.command) {
          case MOVETO:
            return moveTo(world, c.args);            
          case FIRETO:
            return fireTo(world, c.args);
          default:
            return null;        
        }
      }
    
    Die beiden Methoden moveTo() und FireTo() führen dann die entsprechenden Befehle detailliert aus. Um die Übersichtlichkeit zu wahren, werden diese Methoden an dieser Stelle nicht eingebunden.
  • doTick()
    In Abschnitt 5.3.1 wurde zwar beschrieben, dass diese Methode in der Regel die komplexeste ist, jedoch wird in der Beispielimplementierung an dieser Stelle keinerlei weitere Aktion durchgeführt. Die Bewegungen werden bereits von der Oberklasse Ruleset durchgeführt und Explosionen von Kanonenkugeln sind in der Methode targetReached() implementiert.
    Der Programmierer kann hier beliebige Manipulationen vornehmen, solange er die Regeln einhält, die bereits in Abschnitt 5.3.1 genannt wurden.


6.4 Avatar implementieren

Das Framework bietet einen vordefinierte Rahmen für einen Avatar in der Klasse Avatar.class. Diese Klasse ist eine Erweiterung des GameObjects (siehe Abschnitt 5.3.3). Falls Änderungen oder Erweiterungen zum Avatar implementiert werden sollen, dann bietet sich eine Erweiterung der Klasse an. Die zur Verfügung gestellten Methoden sollten dabei nur überschrieben werden, wenn deren Funktionalität vollständig ersetzt wird.

Der ServerThread erzeugt Avatare durch die Methode getClientAvatars(), dort müssen diese Avatar-Implementierungen instanziiert werden.

Die Klasse AvatarImplementation überschreibt die Methode hit(), um das Leveln 6.1des Avatars zu implementieren (siehe auch Abschnitt ). Der Parameter der Methode wird an die Methode der Oberklasse Avatar (super.hit()) durchgereicht und erst danach verarbeitet. Damit wird sichergestellt, dass keine ungewöhnlichen Effekte auftreten.

public int hit(int h) {
  int ret = super.hit(h);
    if (life >= maxlife) {
      life    = 200;
      maxlife+= 100;
      maxspeed+=1.0;
      level++;
    }
  return ret;
}


6.5 ServerThread implementieren

Für den ordnungsgemäßen Betrieb des Server ist die vollständige Implementierung von einigen abstakten Methoden der Klasse ServerThread notwendig. Die wichtigsten Methoden werden hier kurz erläutert. Für detailierte Informationen sollte die JavaDoc zu Rate gezogen werden.

  • SessionTicket loginClient(ClientRequest client)
    Diese Methode wird aufgerufen, sobald sich ein Client mit dem Server verbindet und ein Login anfordert. Als Rückgabewert wird ein SessionTicket erwartet. Für einfache Implementierungen reicht es, wenn einfach ein mit new SessionTicket() erzeugtes SessionTicket zurückgegeben wird.
    Die Beispiel-Implementierung führt keine wirkliche Authentifizierung durch, sondern erzeugt einfach ein SessionTicket für den Client. Es wird lediglich dafür gesorgt, dass ein Client nicht doppelt einloggt.
  • int registerNewClient(ClientRequest client)
    Falls der Client einen Befehl zum Registrieren eines neuen Accounts übermittelt, dann wird diese Methode aufgerufen und ausgeführt.
    Die Implementierung sollte den Account dann dauerhaft anlegen, so dass er in Zukunft bei jedem Login verfügbar ist.
    Die Beispiel-Implementierung reagiert nicht auf diesen Aufruf, d.h. sie ist leer und gibt immer 0 (SUCCESS) zurück. Die Spieler werden nicht permanent gespeichert.
  • Ruleset getRuleset()
    Jedem RegionController, der sich beim Server als frei meldet, sowie jedem Client, der sich beim Server einloggt, wird ein Ruleset übermittelt. Diese wissen dann, wie Befehle zu verarbeiten sind.
    Die Beispiel-Implementierung des Rulesets (RulesetImplementation, siehe 6.3) ist auf ein Minimum beschränkt und kennt daher nur wenige Befehle.
  • Avatar[] getClientAvatars(ClientInfo c)
    Loggt sich ein Client in das System ein, dann müssen seine Avatare an den zuständigen RC-Pool übertragen werden. Die Implementierung kann hier die Avatare aus einer Datenbank oder von sonstigen Speichermedien laden. (siehe Abb. 5.1)
    Die Beispiel-Implementierung erzeugt zufällig einen neuen Avatar vom Typ AvatarImplementaion (siehe 6.4) an einer beliebigen Position und gibt diesen zurück.
  • saveClientAvatars(ClientInfo c, Avatar[] avatars)
    Die Implementierung soll die Avatare des Clients speichern. Die Art der Speicherung ist natürlich abhängig davon, wie sie später wieder durch die Methode getClientAvatars() abgerufen werden. (siehe Abb. 5.3)
    Das die Beispiel-Implementierung immer zufällige Avatare erzeugt, werden die Avatare nicht gespeichert sondern einfach verworfen. Dementsprechend ist die Methode leer.
  • GameWorld getInitialGameWorld()
    Diese Methode ruft das System auf, sobald ServerThread startet. Die Implementierung kann an dieser Stelle dafür sorgen, dass eine persistente Spielewelt aus einer Datenbank geladen wird.
    Die Beispiel-Implementierung erzeugt eine zufällige Welt und gibt sie zurück. Das bedeutet, dass nach dem Beenden des Servers die Welt verloren geht.


6.5.1 Beispiel: ServerImplementation.class

Diese Klasse implementiert die abstrakte Klasse ServerThread und lässt sich als Anwendung starten. Ausgaben und Fehler werden über System.out ausgegeben.

Die Implementierung unterstützt einige Kommandozeilen-Parameter und das Einlesen einer Properties-Datei (siehe 5.2). Diese kann über den Parameter $--$prop dateiname angegeben werden. Als Standard lädt der Server die unter $HOME/.mmpgp2p abgespeicherte Datei server.rc.

Zum Starten des Servers wird folgender Befehl ausgeführt:
java de.tud.dvs1.example.ServerImplementation
Zuvor muss dafür gesorgt werden, dass der CLASSPATH richtig gesetzt ist.

6.5.1.1 main()

Ein Großteil des Programmcodes innerhalb der Methode main() dient lediglich dem Auslesen und Setzen von Parametern und den erwähnten Java-Properties. Das eigentliche Starten des ServerThread umfasst wenige Zeilen:

 0 public static void main (String[] args) {
 1   ServerThread server = new ServerImplementation(prop);
 2        
 3   if (daemon) {
 4     server.setDaemon(true);
 5     System.out.println("SI : Daemon-Modus");
 6   }
 7
 8   ...
 9 
10   try{
11     server.start();
12     ...
13     server.initGameWorld(getTestWorld());
14   }
15 } // main Ende

Zeile 1: diese Zeile muß in jeder Implementierung ausgeführt werden, damit die Parameter des ServerThread gesetzt werden und später richtig gestartet werden kann. Zeile 3-6: ServerThread kann als Daemon gestartet werden. Dies wird hier gesetzt. Zeile 11: nun wird der Thread gestartet. Zeile 13: eine TestWelt wird dem Server als initiale Welt übergeben. Zeile 15: Ende der Methode main(). Der Thread jedoch läuft weiter bis er getötet oder über die Methode stopThread() beendet wird.


6.6 ClientThread implementieren

Zur Implementierung des Clients bedarf es weitaus weniger Schritte als zur Implementierung des Servers. Lediglich ein paar Logging-Funktionen und die Methode stopClientImplementation() müssen implementiert werden. Detailierte Beschreibungen dieser Funktionen sind in der Javadoc zu finden.


6.6.1 Beispiel: ClientImplementation.class

Diese Klasse implementiert die abstrakte Klasse ClientThread und lässt sich als Anwendung starten. Ausgaben und Fehler werden in einem grafischen Fenster ausgegeben. Über die Menüleiste kann das Verhalten gesteuert werden und Informationen abgerufen werden.

6.6.1.1 main()

Wie bei der Implementierung des Servers umfasst der Programmcode vor allem das Auslesen und Setzen von Parametern und Java-Properties. Das eigentliche Starten des ClientThread umfasst wenige Zeilen:

 0 public static void main (String[] args) {
 1   ClientThread client = new ClientImplementation(p);
 2         
 3   try {
 4     // GUI für Programm-Ausgaben starten
 5     javax.swing.SwingUtilities.invokeLater(new Runnable() {
 6       public void run() {
 7                          createAndShowGUI();
 8                         }
 9       });
10             
11     // Start Client Thread
12     client.start();            
13   }
15 } // main Ende

Zeile 1: diese Zeile muß in jeder Implementierung ausgeführt werden, damit die Parameter des ClientThread gesetzt werden und später richtig gestartet werden kann. Zeile 5-9: die grafische Oberfläche des Beispiel-Clients wird gestartet. Zeile 12: nun wird der Thread gestartet. Zeile 15: Ende der Methode main(). Der Thread jedoch läuft weiter bis er getötet, über die Methode stopThread() oder über den Close-Button der grafischen Oberfläche beendet wird.

6.6.1.2 Grafische Oberfläche

Die Implementierung bietet eine grafische Oberfläche zum Steuern des Avatars und zur Ausgabe verschiedener Informationen. Die beiden Reiter ``Client-Log'' und ``RC-Log'' protokollieren Systemausgaben, welche über die Log()-Funktionen vom System erzeugt werden. Der Reiter ``Spielfeld'' ist die Benutzungs-Oberfläche des Spiels, in ihr können Bewegungs- und Feuer-Kommandos befehligt werden. Sie stellt die Objektzustände in einer einfachen Weise grafisch dar.
Figure 6.1: Screenshot der Benutzungsoberfläche der Beispiel-Implementierung
Image screenshot
Über das Menü ``Info'' ist die Ausgabe von Informationen möglich, z.B. die Ausgabe des SessionTickets und der Avatar-Daten. Im Menü ``Spiel'' können Kommandos zum Starten, Pausieren und Wiederaufnehmen des Spiels übermittelt werden. Unter ``Ansicht'' können einige grafische Optionen angepasst werden. Der Menüpunkt ``Client'' bietet zwei wichtige Funktionen, nämlich Login und Logout, sowie die Möglichkeit zum Ein- oder Ausschalten der Komprimierung einiger Kommandos mit GZIP. Und schließlich kann man im Menü ``Datei'' das Programm beenden oder einen BotPlayer starten, der sich dann direkt beim System anmeldet und spielt.

Die Spielregeln sind einfach, die Steuerung funktioniert mit der Maus:

  • Jeder Avatar, dargestellt als Panzer, hat Energie. Diese wird unten links als Balken dargestellt. Beim Feuern verliert der Panzer einen Energiepunkt. Wenn man einen Treffer landet, wird diese Energie wieder aufgefüllt.
    Übersteigt die Energie das Limit, dann steigt der Avatar ein Level auf. Sein Energielimit wird bei jedem Aufstieg ebenfalls erhöht.
  • Mit einem Doppelklick sendet man ein MOVETO-Kommando. Der Avatar bewegt sich dann zum angegebenen Punkt
  • Durch einen Rechtsklick wird ein FIRETO-Kommando ausgeführt. Die Kanonenkugel ``fliegt'' dann zu der Stelle, an der geklickt wurde. Dort explodiert sie dann und zieht Objekte in ihrer Umgebung in Mitleidenschaft.
  • Mit dem Mausrad lässt sich die Umgebung zoomen. Ein Klick auf die mittlere Maustaste zentriert auf dem Avatar, schaltet auf Verfolgungsmodus und stellt den Ursprungszoom wieder her.
  • Mit einem STRG+Doppelklick kann man die Oberfläche auf den geklickten Punkt zentrieren. Der Verfolgungsmodus wird deaktiviert.

http://www.psitronic.de/ti/mmpg/mmpg-peer_to_peer/
Menü

Home
Funstuff
Linux
Hardware
Distributionen
Spiele
Kontakt
Projekte
Java
Webcut
Strength and Honor
A-Mobile
Holy-Wars 2
Holy-Wars 3
-> Dokumentation
Biometrie
Performanzermittlung
-> Mmpg
-> Mmpg-peer to peer
Javadoc
Mmpgp2p-Server
Semantic Web
WSA



- Impressum -
designed using WebCut - Copyright (c) 2001-2008 by Markus Sinner