VJass

Aus Mappedia

Wechseln zu: Navigation, Suche

vJass ist eine Erweiterung der Skriptsprache Jass. Ein Precompiler wie der JassHelper kann sie in normales Jass umwandeln, so dass sie von Warcraft 3 interpretiert werden kann.

Das v vor Jass steht für "very" und nicht wie oft angenommen für Vexorian, den Entwickler des JassHelpers.[1] und Erfinder der Skriptsprache vJass.

Inhaltsverzeichnis

[bearbeiten] Sprachelemente

[bearbeiten] Freiheit bei der Deklaration globaler Variablen

Anders als in Jass können globale Variablen überall deklariert werden. Dazu schreibt man diese in einen globals-Block, welcher sich an einer beliebigen Stelle im Code befinden darf. Beispiel :

    function something takes nothing returns nothing
        set somearray[SOMETHING_INDEX]=4
    endfunction
 
    globals
        constant integer SOMETHING_INDEX = 45
        integer array somearray
    endglobals

[bearbeiten] Debug-Präprozessor

Schreibt man das Schlüsselwort "debug" an den Anfang einer Zeile, so wird diese nur im Debug-Modus beim Umwandeln des vJass-Codes in Jass-Code verwendet. Ansonsten wird sie vom Precompiler ignoriert. Beispiel:

   function Something takes integer a returns nothing
       debug call BJDebugMsg("a is "+I2S(a)) // diese Zeile wird nur im Debug-Modus beachtet
       call KillNUnits(a)
   endfunction


[bearbeiten] Gültigkeitsbereiche

Gültigkeitsbereiche dienen dazu, Code besser zu strukturieren und Funktionen und Variablen gegen Zugriffe von Außen abzusichern. Innerhalb eines Gültigkeitsbreichs können die Schlüsselwörter public und private benutzt werden, um den möglichen Zugriff von Außen zu bestimmen. Außerdem können Gültigkeitsbereiche ineinander verschachtelt werden und eine Initialisierungsfunktion verwenden, welche keine Argumente entgegennehmen darf und während der Karten-Initialisierung aufgerufen wird. Gültigkeitsbereiche werden mit den Schlüsselwörtern "scope" und "endscope" gekennzeichnet. Beispiel:

[bearbeiten] Bibliotheken

Bibliotheken sind Gültigkeitsbereiche, die andere Bibliotheken als Vorraussetzung angeben können. Bibliotheken werden beim Umwandeln in Jass-Code automatisch je nach ihren Voraussetzungen sortiert. Setzen zwei Bibliotheken jeweils die andere Biblioth als Abhängigkeit voraus, so erzeugt dies einen Syntaxfehler. Wie Gültigkeitsbereiche können Bibliotheken ebenfalls eine Initialisierungsfunktion verwenden, welche während der Karten-Initialisierung aufgerufen wird und keine Argumente entgegennehmen darf. Anders als Gültigkeitsbereiche jedoch, können Bibliotheken nicht ineinander verschachtelt werden. Jedoch können sie selbst Gültigkeitsbereiche enthalten. Bibliothenen werden mit den Schlüsselwörtern "library" und "endlibrary" gekennzeichnet. Mittels des Schlüsselworts "initializer" und "requires", "uses" oder "needs" können die optionale Initialisierungsfunktion und die optionalen Abhängigkeiten angegeben werden. Eine einzelne Abhängigkeit kann ebenfalls für sich mit dem vorangestellten Schlüsselwort "optional" als optional gekennzeichnet werden, was besonders bei Bibliotheken, welche zum Beispiel nur im Debug-Modus vorhanden sind, von Vorteil ist. Beispiel:

	library MyLibrary initializer init requires AnotherLibrary, optional DebugLibrary
	
		private function init takes nothing returns nothing
		endfunction

	endlibrary

[bearbeiten] Text-Makros

Text-Makros ist ein Sprachelement, dass einen Code-Block kopiert und bestimmte Bezeichner in diesem mit Parametern ersetzt. Text-Makro-Bereiche werden mit den Präprozessoranweisungen "textmacro" und "endtextmacro" gekennzeichnet.

[bearbeiten] Structs

Structs erlauben dem vJass-Benutzer, eigene Objekte zu erstellen und diesen eigene Methoden und Elemente zuzuordnen. Dies verläuft so:

 struct SomeData
   unit datunit
   real x
 endstruct

Erstellt wird eine struct mit der Anweisung

 local Structtype Structname = Structtype.create()

[bearbeiten] Methoden und Elemente

Jede struct kann auch Methoden besitzen. Beispiel:

 method test takes nothing returns nothing
 endmethod
Auf Methoden wird mittels
struct-Instanz.Methodenname(Argumente)
zugegriffen. Auf Variablen (Member bzw. Elemente) der struct wird mittels
struct-Instanz.Elementname
zugegriffen. Auf statische Elemente und Methoden wird dagegen mittels
struct-Name.Methodenname(Argumente)
bzw.
struct-Name.Elementname
zugegriffen.

Es gibt auch bestimmte Methoden, die zu jeder struct schon standardmäßig dazugehören. Dazu zählt die create-Methode (der Konstruktor), die onDestroy-Methode (der Destruktor), die onInit-Methode (der Initialisator), die allocate-Methode (nicht überschreibbarer Konstruktor) und die destroy-Methode (nicht überschreibbarer Destruktor). Man kann sie verwenden, indem man sie als Methoden deklariert (ausgenommen der allocate- und der destroy-Methode). Die create-Methode wird beim Erstellen einer struct-Instanz aufgerufen und kann in der struct-Definition auch überschrieben werden, die onDestroy-Methode wird aufgerufen wenn man die destroy-Methode benutzt, die onInit-Methode wird während der Karteninitialisierung aufgerufen, die allocate-Methode sollte von der create-Methode aufgerufen werden (Dies kann beim Überschreiben der Methode verhindert werden) und die destroy-Methode wird vom Benutzer aufgerufen, wenn er eine struct-Instanz löschen möchte. Beispiel für eine Überschreibung der create-Methode (Wenn man der Methode Parameter hinzufügt, um den Code zu verkürzen):

struct test
  private unit caster //privates Element der Struktur (geschützt vor Zugriffen von außen und von Kind-structs)

  //überschriebener Konstruktor
  public static method create takes unit U returns test
    local test this = test.allocate() //allocate nicht vergessen, um eine Instanz zu erzeugen
    set this.caster = U //Startelemente setzen
    return this //erzeugte Instanz an Benutzer zurückgeben
  endmethod
endstruct

Man sieht, dass die Methode eine Instanz, die durch typ.allocate() erstellt wird, zurückgeben muss, um zu funktionieren.

Beispiel für eine Definition der onDestroy-Methode:

struct test2
  lightning l //öffentliches Element der Struktur (offen für jede Art von Zugriff)

  public method onDestroy takes nothing returns nothing
    call DestroyLightning(this.l) //Element-Inhalt wird zerstört
    set this.l = null //nullen gegen Memory-Leaks
  endmethod
endstruct

Struct-Member (Elemente) müssen nicht unbedingt genullt werden, wie es bei anderen Handles üblich ist, da sie in globale Arrays umgewandelt werden. Structs haben auch bei der Benutzung von Timern einen Vorteil da man mit ihrer Hilfe nicht immer jeden Wert einzeln durch Systeme wie Local Handle Vars in andere Funktionen transportieren muss. Man kann weiter Handle Vars benutzen, aber dieses System ist langsam und nicht bugfrei, weshalb Systeme wie TT(Timer Ticker) oder ABCT bzw. ABC empfohlen werden (allesamt auf wc3campaigns zu downloaden).

Bei Methoden gilt es zu beachten, dass diese normalerweise vom JassHelper in Auslöser-Aktionen umgewandelt und einem bei bestimmten Auslöser hinzugefügt werden, welcher bei einem Aufruf der Methode mittels TriggerEvaluate aufgerufen wird. Der Sinn des Ganzen besteht darin, dass man das Problem der Deklarationsreihenfolge in Jass umgeht, da in Jass eine Funktion erst nach ihrerer Deklaration aufgerufen wird. Laut Vexorian, dem Erfinder der Sprache vJass, sollten Methoden nur dann per eigenem Auslöser aufgerufen werden, wenn es tatsächlich zu einem Aufruf vor ihrer Deklaration kommt.[2] Will man den TriggerEvaluate-Aufruf umgehen, weil man zum Beispiel die Funktion TriggerSleepAction in einer Methode verwendet, so sollte man .execute benutzen.

[bearbeiten] Schnittstellen

Schnittstellen (englisch interfaces) bieten eine zusätzliche Möglichkeit der Vererbung. Eine Schnittstelle kann, genau wie eine Struktur, Elemente und Methoden enthalten. Allerdings werden bei Schnittstellen im Gegensatz zu Strukturen Methoden nicht definiert, sondern lediglich deklariert. Schnittstellen sind allein dazu gedacht, von einer Struktur geerbt zu werden. Dabei werden die Elemente der Schnittstelle genau wie bei Strukturen auf die Kindstruktur übertragen. Die Methoden der Schnittstelle haben dagegen einen anderen Sinn als eine Übetragung. Sie denen dazu, dass der Benutzer gezwungen ist, sie in seiner Struktur zu definieren. Eine Ausnahme bilden hierbei Methoden, die einen standardmäßigen Rückgabewert, eine Besonderheit, die nur für Schnittstellenmethoden gilt, besitzen. Schnittstellen können dazu verwendet werden die Behandlung verschiedener Strukturtypen zu abstrahieren ohne irgendeine Verhaltensweise, bis auf die Parameer, den Rückgabewert und den standardmäßigen Rückgabewert, der benötigten Methoden vorzugeben. Seit der Einführung des Schlüsselwortes stub sind sie jedoch teilweise überflüssig geworden, da man dadurch auch Methoden geerbter Strukturen überschreiben konnte. Eine Schnittstellen wird nach dem Schema

interface Schnittstellenname
endinterface

definiert. Zwischen den Zeilen mit den Schlüsselwörtern interface und endinterface können Element- und Methodendeklarationen stehen:

interface Schnittstellenname
	private integer m_peter

	public method subtract takes integer x, integer y returns integer defaults 0
endinterface

Mittels des Schlüsselwortes defaults können standardmäßige Rückgabewerte von Methoden definiert werden. Dies hat zur Folge, dass die Methode nicht mehr von ihrer Kindstruktur definiert werden muss. Wird sie es nicht, so bei sämtlichen Aufrufen der Methode entweder gar nichts oder der standardmäßige Rückgabewert eingetragen. Wie bei anderen Strukturen werden auch Schnittstellen mittels des Schlüsselwortes extends geerbt:

struct Strukturname extends Schnittstellenname
	public method subtract takes integer x, integer y returns integer
		return x - y
	endmethod
endstruct

[bearbeiten] Externe Script-Dateien importieren

In einigen Fällen kann es durchaus nützlich sein mit externen Script-Dateien zu arbeiten, anstatt den Code im Header oder in mehreren Auslösern zu lagern. Zum Beispiel haben wohl die meisten Linux-Anwender das Problem, den Editor nicht richtig oder gar nicht benutzen zu können. Sie sind darauf angewiesen mit externen Script-Dateien zu arbeiten (so auch Vexorian selbst). Da es aber sehr zeitaufwändig wäre, die Dateien jedes Mal zu einem Kartenskript zu vereinigen oder sie irgendwie von Hand in der Karte einzufügen, stellt vJass hierfür das sogenannte Import-Makro zur Verfügung:

//! import "relativer oder absoluter Dateipfad"

Dieses Makro kann überall dort stehen, wo auch normaler vJass-Code stehen könnte und bindet den in der importierten Script-Datei enthaltenen Code, beim Speichern der Karte direkt an der Stelle des Makros ein. Die eingebundene Script-Datei kann selbst nochmals Import-Makro-Anweisungen enthalten, wodurch sich eine Art Dateibaum erstellen lässt. Falls man die Script-Dateien nicht im selben Verzeichnis wie die Kartendatei lagern möchte, so muss man beim Importieren entweder den absoluten Pfad der Script-Datei angeben, oder man fügt einen weiteren Eintrag in der jasshelper.conf-Datei, welche sich normalerweise im obersten Verzeichnis des JassNewGenPacks befindet, unter der Kategorie "[lookupfolders]" hinzu. Script-Dateien im Verzeichnis des Eintrags werden dann wie Script-Dateien, die sich im Verzeichnis oder Unterverzeichnissen der Kartedatei befinden behandelt.


[bearbeiten] Zeilenumbruchbeheber

Ersetzt Zeilenumbrüche in Zeichenketten durch \n. Dadurch wird ein Problem mit PJass behoben, wodurch die Zeilenangabe bei Fehlermeldungen falsch ist.

[bearbeiten] Kritik

Die Sprache wird des Öfteren aufgrund einiger Mängel, die bei gängigen Programmiersprachen in dieser Form meist nicht auftreten, kritisiert. Zu den Kritikpunkten zählen unter anderem:

  • Fehlen des Schlüsselwortes "protected"
  • Fehlen einer guten Unterstützung generischer Programmierung (keine verschachtelten Textmakro(aufrufe), keine privaten Implementationen von Modulen)
  • Fehlen von einfacheren Sprachkonstrukten wie einer for-Schleife oder eines ++-Operators
  • Schlüsselwörter wie "delegate" und "operator", die mehr oder weniger selten zu gebrauchende Funktionalitäten zur Verfügung stellen
  • das Vorhandensein von Gültigkeitsbereichen und Bibliotheken, anstatt einer Verschachtelungsmöglichkeit von Bibliotheken
  • der :-Operator für Arrayzugriffe

Des Weiteren benötigte das Beheben von Fehlern im einzigen verfügbaren Compiler, dem JassHelper, oft sehr lange. Der Benutzer Vexorian implementierte des Öfteren neuere Sprachkonstrukte, obwohl sich noch elementare Fehler in seinem Programm befanden. Die Diskussion über einige der obigen Kritikpunkte führte oftmals dazu, dass Vexorian seine Meinung verteidigte und die Sprachkonstrukte beibehielt bzw. nicht implementierte. Das heißt, dass die Sprache hauptsächlich nicht in der Gemeinschaft, sondern von Vexorian selbst entworfen wurde.

[bearbeiten] Quellen

[bearbeiten] Weblinks

Persönliche Werkzeuge
Besucherstatistiken
kostenlose Statistik
Seit dem 25. Oktober 2006 18:00 Uhr