Plugin Tutorial/de

## Einleitung

Dieses Tutorial wurde von diesem Thread kopiert. Es wurde ursprünglich von **Adamki11s** geschrieben. Seitdem wurde es mit mehreren Beispielen erweitert.

Adamki11s Bukkit Profil Seite

Nach beenden dieses Tutorials könntest du auf **Adamki11s'** "Extras" Bibliothek nachsehen welche verschiedene Erweiterte Funktionen bietet.Extras Bibliothek Forum Thread.

## Java lernen

Diese Tutorials benötigen Grundkentnisse in der Programmiersprache Java. Wenn du nichts oder nicht viel über Java weist solltest du den Links unten folgen, weil sie dir eine Menge helfen könnten!

### Java Video Tutorials

* GTOTechnology - Englische Bukkit Tutorials für Anfänger
* Dinnerbone - Großartige Plugin Tutorials bei Bukkit's eigenen Dinnerbone
* Thenewboston - Viele Hervorragende Videos sind hier zu finden
* JavaVideoTutes.com - Deckt eine Vielzahl von Themen ab.

### Java Text Tutorials

* Oracle Documentation (Eine Firma die Java unterstützt)
* Java2s.com - Alles zum Thema Java ist hier zu finden
* Java 101 - Detailliert geschrieben Tutorials
* Deutsches Tutorial - Sehr ausführliches, deutsches Java-Tutorial

Wenn du bis jetzt nicht mit der Programmiersprache Java gearbeitet hast solltest du einen Blick auf einige Tutorials werfen.

## Java IDEs

Bevor du ein Plugin entwickeln (oder Java lernen) kannst, wirst du eine IDE (Integrated Development Environment) installieren müssen. Dieses ist ein Programm welches du zum kompilieren und debuggen deiner Plugins benötigst. Es existieren derzeit drei populäre IDEs für Java: Eclipse, Netbeans, und IntelliJ IDEA. Eclipse ist das populärste unter Bukkit Entwicklern, während IntelliJ zum größten Teil in der Industrie verwendet wird. Wenn die Entwicklung in Java komplettes Neuland für dich ist, dann ist es empfehlenswert Eclipse zu nutzen, da diese IDE in den meisten Tutorials verwendet wird. Die empfohlene Eclipse Version welche du runterladen solltest ist Eclipse IDE for Java Developers.

Ein exzellentes Eclipse Tutorial kannst du hier finden. Es wurde für Eclipse 3.3 geschrieben, aber das Konzept lässt sich auch auf neuere Versionen anwenden.

Für eine Anleitung um mit IntelliJ zu starten, schaust du dir bitte das folgenden Tutorial an: Getting Started with IntelliJ

## Starten eines Plugin Projekts

#### Ein Projekt erstellen

Vor dem Start wirst du deinen Workspace und Dateien in Eclipse einrichten müssen. Starte Eclipse und erstelle ein neues Projekt in dem du *File > New > Java Project:* anwählst.

Nenne das Projekt so wie du willst, dann klick dich durch den *new project wizard* und folge den Anweisungen auf dem Bildschirm. Ein Ordner wird in der *Package Explorer* Seitenleiste zu deiner linken erscheinen; Durch einen "links-klick" auf den kleinen Pfeil daneben, wird dir der Inhalt deines Projekts angezeigt.

### Einbinden der Bukkit API

Bevor du mit der Entwicklung deines Plugins beginnst, wirst du die Bukkit API als *external JAR* in dein Projekt einbinden müssen. Du kannst natürlich auch andere APIs welche du nutzen möchtest in dein Projekt einbinden z.B. Permissions.

Die aktuellste Bukkit API kann hier runtergeladen werden: (Funktioniert nichtmehr!!!) Bukkit API - Development Snapshot

Rechts Klick auf deinen Projekt-Ordner im *Package Explorer* im Panel zu deiner linken und dann auf *Properties*, dort wählst du *Java Build Path* auf der linken Seite aus und der Dialog in deiner *Properties Box* sollte sich nun ändern. Klicke auf *Add External JARs* und wähle den Pfad zu deiner runtergeladenen Bukkit API aus.

### Bukkit Javadocs

Wenn du etwas Erfahrung mit Eclipse und Java hast, dann wirst du wissen, dass wenn du mit deinem Mauszeiger über eine *built-in* Klasse oder Methode fährst, eine gelbe Box aufgeht welche die Dokumentation der Klassen oder Methoden beinhaltet. Dieses ist bekannt als Javadoc und ist auch auf der Oracle Website online zugänglich. Bukkit hat auch eine solche Dokumentation welche oftmals nützliche Beschreibungen der einzelnen Methoden oder Klassen der API beinhalten. Diese ist auch hier online zugänglich. Damit diese Dokumentation auch in Eclipse verfügbar ist, so dass ein Popup erscheint sobald eine Bukkit Methode oder Klasse mit dem Mauszeiger berührt wird, Ist es nötig dass diese Dokumentation erst hinzugefügt wird. Dazu machst du als erstes einen Rechtsklick auf die Bukkit JAR welche unter "Referenced Libraries" in deinem Project Explorer aufgelistet wird und klickst auf "Properties". Wähle "Javadoc Location"  auf der linken Seite des Fensters aus und füge die folgende URL "http://jd.bukkit.org/apidocs/" (ohne Anführungszeichen)  in die Textbox unter "Javadoc URL" ein. Es sollte wie folgt aussehen:

Klicke auf *validate* und dann klicke *OK*. Fertig! Nun sind die Bukkit Javadocs mit dem Bukkit Quellcode verbunden und du kannst die hilfreiche Dokumentation innerhalb von Eclipse aufrufen.

### Beginne mit deinem Plugin

Nun musst du ein 'Package' erstellen welches alle Java Klassen beinhalten wird die wir benutzen. Rechtsklicke den Ordner mit dem Namen "src" dann auf *New > Package*:

Benenne dein Package wie folgt:

```
- Wenn du einen Domain Namen hast, dann würde dein Packagename der Domain Name rückwärts sein.
 - Bsp: i-am-a-bukkit-developer.com dein Package würde dann com.i-am-a-bukkit-developer heißen source

- Du hast keine Domain? Ordne nach bevorzugter Methode.

 - **Option 1** Erstelle einen Account auf einer Source Control Site wie z.B. GitHub oder SourceForge.
   - Für GitHub folgst du den Anweisungen hier und wirst dann eine Domain haben, so würde dein Packagename com.github.<username> sein.

 - **Option 2** Du kannst deine E-Mail Adresse nutzen.  Bsp: <username>@gmail.com würde dann com.gmail.<username> sein

 - **Option 3** Das ist die letzte bevorzugte Methode.
   Nutze einfach irgendeinen einzigartigen Packagename und nochmals, nutze diese Option als die letzte Möglichkeit.

```

Da sind einige Dinge mit welchen dein Packagename NICHT beginnen darf:

```
- org.bukkit
- net.bukkit
- com.bukkit

```

Wenn du den Basis Packagenamen hast, dann war es das erstmal mit dem Packagenamen. Lass uns die GitHub Domain als Beispiel benutzen. Wenn du ein Plugin erstellst welches "TestPlugin" heißt, dann würde dein voller Packagename wie folgt aussehen: "com.github.<username>.TestPlugin"

Nun da wir unser Projekt fertig aufgesetzt haben, können wir jetzt damit beginnen Klassen hinzuzufügen und unser Plugin zu schreiben. Es ist immer ein gutes Training die Hauptklasse (main class) erst zu erstellen und ihr dann den Namen deines Projekts zu geben. Rechtsklick auf den "src" Ordner wie zuvor und klicke  *New > Class*. Die Hauptklasse sollte möglichst immer den selben Namen wie das Plugin haben. Zum Beispiel, wenn ich ein Plugin mit dem Namen "TestPlugin" erstelle, dann sollte die Hauptklasse auch "TestPlugin" heißen.

Du hast nun dein Projekt mit der Hauptdatei erstellt. Um Bukkit zu erlauben es zu 'sehen' müssen wir noch folgende **plugin.yml** Datei hinzufügen. Diese Datei wird essentielle Informationen beinhalten und ohne diese wird dein Plugin NICHT laufen. Dieses mal machen wir einen Rechtsklick auf den Projekt Ordner, NICHT auf den "src" Ordner. Klicke *New > File*. Nenne die Datei "**plugin.yml**" und klicke *OK*. Eclipse wird deine momentan noch leere **plugin.yml** Datei im default Text Editor öffnen. *(Hinweis: Wenn du deinen Workspace organisiert halten willst, dann schließe den Text Editor und ziehe die **plugin.yml** Datei in den Main Workspace (zu deiner Rechten) und du wirst die Datei innerhalb von Eclipse bearbeiten können.)* Da sind zwei essentielle Dinge die du hinzufügen musst; Deine Hauptklassen Referenz und Commands/Usage. Die simpelste **plugin.yml** Datei würde wie folgt aussehen :

> ````
> name: <PluginName>
> main: <packagename>.<PluginName>
> version: <Version Number>
> ````

Merke: Der Packagename beinhaltet oftmals den Plugin Namen, also sei nicht überrascht wenn du das hier <pluginname>.<pluginname> am Ende der zweiten Zeile siehst!

## onEnable() und onDisable()

Diese Funktionen werden immer dann aufgerufen wenn ein Plugin enabled/disabled wird. Per default wird sich dein Plugin automatisch enablen wenn es geladen wird so dass du deine Events registrieren kannst und Debug Output ausgeben kannst. onEnable() ist das erste was Bukkit aus deinem Plugin laden wird und es wird alles beinhalten, was dein Plugin zum laufen benötigt!

### Einführung zu onEnable() und onDisable()

Erstelle die Methoden `**onEnable()**` und `**onDisable()**` innerhalb der Hauptklasse welche wir zuvor erstellt haben wie folgt:

>
> ```
> public void onEnable(){
>
> }
>
> public void onDisable(){
>
> }
>
> ```
>

In diesem Moment haben die Methoden noch keinerlei Funktion, allerdings solltest du bemerkt haben, dass es eine Fehlermeldung gibt. Das passiert, weil wir der Hauptklasse erst sagen müssen, dass sie die Funktionalität des Plugins erweitern soll ('extends'). Ändere den Code am Beginn deiner Klasse (direkt unter dem Packagename) von diesem:

>
> ```
> Class <classname> {}
>
> ```
>

Zu diesem:

>
> ```
> Class <classname> extends JavaPlugin {}
>
> ```
>

Nach dem hinzufügen dieses Codes, solltes du eine rote Linie unterhalb von *JavaPlugin* sehen, diese sagt dir, dass etwas nicht korrekt ist. Um das zu beheben, fährst du mit deiner Maus einfach über den markierten Code und klickst bei dem aufgehenden Popup auf `**Import 'JavaPlugin' (org.bukkit.plugin.java)**`.

### Eine Nachricht mittels Logger ausgeben

Wir werden nun eine simple Nachricht in der Serverkonsole ausgeben, um mitzuteilen wann das Plugin aktiviert oder deaktiviert wird. Als erstes benötigen wir ein *logger Objekt*, um etwas in der Konsole auszugeben. Dieses bekommen wir in der Hauptklasse durch ein simples

>
> ```
> this.getLogger()
>
> ```
>

Dann können wir innerhalb der `**onEnable()**` Funktion eine Nachricht ausgeben, wenn das Plugin aktiviert wurde:

>
> ```
> log.info("Your plugin has been enabled.");
>
> ```
>

Dasselbe funktioniert überall in der Hauptklasse, die nun so aussehen könnte:

>
> ```
> package me.<yourname>.<pluginname>;
>
> import java.util.logging.Logger;
> import org.bukkit.plugin.java.JavaPlugin;
>
> public Class <classname> extends JavaPlugin {
>  public void onEnable(){
>  this.getLogger().info("Your plugin has been enabled!");
>  }
>
>  public void onDisable(){
>  this.getLogger().info("Your plugin has been disabled.");
>  }
> }
>
> ```
>

Das solltest du nicht tun; auch wenn viele Plugins so in die Konsole schreiben, dass sie aktiviert wurden:
Bukkit kümmert sich schon darum, dass schon im Chat steht, wenn dein Plugin aktiviert wurde.

## Listener

**Einführung**

Mit **Ereignissen/Events** teilt der CraftBukkit-Server Ihrem Plugin mit, dass etwas auf der Welt passiert ist. Bukkit definiert viele Ereignisse/Events in mehrere Kategorien; z.B. Spielerereignisse (Spieler hat den Server betreten, Spieler hat auf einem Block geklickt, Spieler ist gestorben, Spieler ist wiederbelebt worden...), Blockereignisse (Block platziert, Block zerstört, Blocknachbar geändert ...), Entitätsereignisse (ein Mob hat dich ins Visier genommen, ein Creeper explodiert  ...), weltweite Ereignisse (eine geladene oder entladene Welt, ein geladenes oder entladenes Stück) und vieles mehr.  Aus unbekannten Gründen gibt es keine Links mehr zu offiziellen Javadocs, da alle offline geschaltet wurden.

 *Siehe dazu: Introduction to the New Event System*
## Befehle/Commands

### Die onCommand() Methode

So, jetzt weißt du wie man Events registriert und wie man etwas macht wenn diese ausgelöst werden, aber was ist wenn du nur etwas machen möchtest, wenn ein Befehl/Command ausgeführt wurde? Richtig, du nutzt die `**onCommand**` Methode. Dieser Code wird immer dann ausgeführt, wenn ein Spieler einen Befehl mit vorangestelltem Slash ("/") in den Chat eingibt. z.B. Bei die Eingabe von "/do something" würde die Methode `**onCommand**` aufrufen. In diesem Fall würde nichts passieren, da noch kein Code dafür geschrieben wurde.

Vermeide die Benutzung von Befehlen/Commands welche in Bukkit bereits existieren und bedenke wie einzigartig dein Command sein sollte. z.B. das "give" Command wird bereits von unzähligen Plugins verwendet und wenn du nur noch so ein Command wie "give" erstellst, wird dein Plugin sehr schnell inkompatibel zu manch anderen Plugins werden.

Die `**onCommand**` Methode muss immer einen boolean Wert zurückgeben - entweder true oder false. Wenn der zurückgegebene Wert true ist dann wirst du kein bemerkenswertes Event sehen. Wenn die Methode false zurück gibt, dann wird der Inhalt deiner Plugin Dateien zurückgegeben 'usage: property' und zeigt dem User eine Nachricht an wie der Befehl zu benutzen ist, wie in der **plugin.yml** Datei angegeben.

Wenn `**onCommand**` genutzt wird, dann solltest du immer vier Parameter registrieren.

* `**CommandSender sender**` - Welcher den Befehl sendet

* `**Command cmd**` - Der Befehl welcher ausgeführt wird

* `**String commandLabel**` - Das Alias welches für den Befehl genutzt wird

* `**String[] args**` - Ein Array von zusätzliches Argumenten, z.B. das schreiben von */hello abc def* würde *abc* in args[0] stecken, und *def* in args[1]

#### Einen Befehl erstellen

>
> ```
> public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args){
>  if(cmd.getName().equalsIgnoreCase("basic")){ // Wenn der Spieler /basic eingibt, dann tue das folgende...
>  //Tuhe das
>  return true;
>  } // Wenn das passiert, wird die Funktion abbrechen und true als Wert zurückgeben. Wenn nicht, dann wird false als Wert zurückgegeben.
>  return false;
> }
>
> ```
>

Wenn du die `**onCommand**` Funktion schreibst, ist es immer eine gute Übung return false am Ende der Funktion zurückzugeben. Die Rückgabe von false zeigt dem User dann die korrekt Benutzung des Befehls an, so wie er in der **plugin.yml** definiert wurde (siehe unten). Das ist der Weg mit welchem die Hilfe angezeigt wird, wenn etwas falsch eingegeben wird. Sobald ein Wert zurückgegeben wird, die Funktion also true ist, wird die Funktion verlassen und jeglicher Code darunter wird nicht mehr ausgeführt.

`**.equalsIgnoreCase("basic")**` bedeutet nur dass zwischen Groß- und Kleinschreibung nicht unterschieden wird. Zum Beispiel, der String "BAsIc" und "BasiC" würden beide gleich dem Command *basic* sein und der Code würde ausgeführt werden.

### Befehl/Command zur Plugin.yml hinzufügen

Es ist außerdem wichtig den Befehl der **plugin.yml** Datei hinzuzufügen. Füge das folgende am Ende der **plugin.yml** Datei ein:

> ````
>  description: This is a demo command.
>  usage: /<command> [player]
>  permission: <plugin name>.basic
>  permission-message: You don't have <permission>
>
> ````
>
>

* `**basic**` - Der Name des Befehls.

* `**description**` - Die Beschreibung des Befehls.

* `**usage**` - Der Hilfe Dialog, welchen die User sehen, wenn die Methode `**onCommand**` false zurück gibt. Beschreibe deutlich was der Befehl macht und wie er zu benutzen ist.

* `**permission**` - Das wird genutzt um einigen Hilfe Plugins zu sagen, welche Befehle bei welchen Permissions angezeigt werden dürfen.

* `**permission-message**` - Diese Nachricht wird ausgegeben, wenn die benötigten Rechte zum Ausführen des Befehls nicht vorhanden sind, es aber dennoch versucht wird.

Merke: Die YML-Dateien nutzen zwei bis vier Leerzeichen anstelle von Tabs. Tabs sind nicht gestattet und führen zu Fehlermeldungen.

### Konsolen Befehle vs. Player Befehle

Dir ist bestimmt bereits der `**CommandSender sender**` Parameter oben aufgefallen. `**CommandSender**` ist ein Bukkit Interface welches zwei nützliche (für Plugin Entwickler) Implementationen besitzt: `**Player**` und `**ConsoleCommandSender**` (um genau zu sein ist `**Player**` auch ein Interface).

Wenn du dein Plugin schreibst, dann ist es eine sehr gute Idee sicher zu stellen, dass dein Befehl von der Console ausgeführt werden *kann* und das Befehle wirklich nur von eingeloggten Spielern ausgeführt werden können. Manche Plugins geben einfach nur zurück ob der Sender kein Spieler ist (z.B. jemand versucht einen Befehl des Plugins von der Console auszuführen), auch wenn solche Befehle einen Sinn ergeben, dass sie von der Console ausgeführt werden (z.B. wechseln des Wetters auf dem Server).

Einen Weg um dieses zu machen ist:

>
> ```
> public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
>  Player player = null;
>  if (sender instanceof Player) {
>  player = (Player) sender;
>  }
>
>  if (cmd.getName().equalsIgnoreCase("basic")){ // Wenn der Spieler /basic eingegeben hat, dann mache das folgende...
>  // tue etwas...
>  return true;
>  } else if (cmd.getName().equalsIgnoreCase("basic2")) {
>  if (player == null) {
>  sender.sendMessage("this command can only be run by a player");
>  } else {
>  // tue irgendwas anderes...
>  }
>  return true;
>  }
>  return false;
> }
>
> ```
>

In diesem Beispiel kann der Befehl **basic** von jedem ausgeführt werden - ein eingeloggter Spieler, oder der Server Operator in der Console. Aber der Befehl **basic2** kann nur von eingeloggten Spielern ausgeführt werden.

Hauptsächlich solltest du versuchen so viele Befehle wie möglich für beide ausführbar zu machen, für Spieler sowie auch für die Console. Befehle welche einen eingeloggten Spieler *benötigen* können den Mechanismus nutzen welcher oben genannt wird um zu überprüfen ob der `**CommandSender**` aktuell ein Spieler ist bevor fortgefahren wird.
Solche Befehle wären üblicherweise von einigen Eigenschaften des Spielers abhängig, z.B. braucht ein Teleportationsbefehl einen Spieler zum Teleportieren, ein Item gebender Befehl braucht einen Spieler, dem das Item gegeben werden soll...

Wenn du weiter fortschreiten möchtest, könntest du weitere Kontrollen der Befehlargumente einfügen, sodass z.B. ein Teleportationsbefehl, *wenn und nur wenn* der Name eines Spieler mitgeliefert wird, ausgeführt wird.

### Eine separate CommandExecutor Klasse benutzen

Die Beispiele oben haben die `**onCommand()**` Methode einfach in die Hauptklasse des Plugins gesteckt. Für kleine Plugins ist das in Ordnung, aber wenn du etwas umfangreicheres schreibst, könnte es Sinn ergeben, deine `**onCommand()**` Methode in eine eigene Klasse zu setzen. Zum Glück ist das nicht allzu schwer:

* Erstelle eine neue Klasse im Package deines Plugins. Nenne sie in etwa **MyPluginCommandExecutor** (natürlich solltest du **MyPlugin** durch den Namen deines Plugins ersetzen). Diese Klasse *muss* das Bukkit **CommandExecutor** Interface implementieren.

* In der `**onEnable()**` Methode deines Plugins musst du eine Instanz deiner neuen **CommandExecutor** Klasse erstellen und sie dann so aufrufen: `getCommand("basic").setExecutor(myExecutor);`, wobei "basic" der Befehl, den du verarbeiten möchtest, und `myExecutor` die erstellte Instanz ist.

Am besten wird das anhand eines Beispiels erklärt:

**MyPlugin.java** (die Hauptklasse des Plugins):

>
> ```
> private MyPluginCommandExecutor myExecutor;
> @Override
> public void onEnable() {
>  // ....
>
>  myExecutor = new MyPluginCommandExecutor(this);
>  getCommand("basic").setExecutor(myExecutor);
>
>  // ...
> }
>
> ```
>

**MyPluginCommandExecutor.java**:

>
> ```
> public class MyPluginCommandExecutor implements CommandExecutor {
>
>  private MyPlugin plugin;
>
>  public MyPluginCommandExecutor(MyPlugin plugin) {
>  this.plugin = plugin;
>  }
>
>  @Override
>  public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
>  // ... implementation exactly as before ...
>  }
> }
>
> ```
>

Beachte wie eine Instanz von der Hauptklasse des Plugins (MyPlugin) an den Konstruktor von **MyPluginCommandExecutor** übergeben wird. Dadurch kann vom CommandExecutor aus einfach auf die Methoden des Hauptplugins zugegriffen werden, falls nötig.

Durch diese Einteilung kann der Code besser organisiert werden - wenn die Methode zur Befehlsausführung `**onCommand()**` groß und komplex wird, kann sie in Subroutinen aufgeteilt werden, um den Code übersichtlicher zu machen.

Beachte: Wenn dein Plugin mehrere Befehle hat, musst du für jeden Befehl einzeln den command executor setzen.

## Ein sicheres "onCommand" schreiben

Wenn Du ein "onCommand" schreibst, ist es wichtig, dass du nicht davon ausgehst, dass alle Informationen korrekt eingegeben wurden. Manchmal ist es zusätzlich nötig, sicherzustellen, dass der Benutzer ein Spieler ist. Einige Dinge solltest Du Dir also merken:

### Stelle sicher, dass der Sender ein Spieler ist

Schon ein einfacher Code wie dieser, macht das möglich:

>
> ```
> public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args){
>  if (!(sender instanceof Player)) {
>  sender.sendMessage(ChatColor.RED + "Du musst ein Spieler sein!");
>  return true;
>  }
>  Player player = (Player) sender;
> }
>
> ```
>

### Die Länge der Argumente überprüfen

Nimm nicht immer an, dass ein Spieler die richtige Länge von Argumenten verwendet. Um Fehler zu vermeiden, verwende diesen Code:

>
> ```
> public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args){
>  if (args.length > 4) {
>  sender.sendMessage(ChatColor.RED + "Zu viele Argumente!");
>  return true;
>  }
>  if (args.length < 2) {
>  sender.sendMessage(ChatColor.RED + "Nicht genug Argumente!");
>  return true;
>  }
> }
>
> ```
>

### Beim herausfinden eines Spielers durch seinen Namen, sei sicher, dass dieser online ist

Manchmal kommt es vor, dass ein Befehl auf einen Spieler aufbaut, der nicht auf deinem Server ist; deswegen sollte in einer onCommand-Methode immer als erstes ein `OfflinePlayer` benutzt werden.
Eine Ausnahme dabei ist natürlich der Spieler, der den Command gesendet hat.

>
> ```
> public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args){
>  OfflinePlayer other = (Bukkit.getServer().getOfflinePlayer(args[0]);
>  if (other.isOnline()) {
>  // Nun kann ein 'echter' Spieler erstellt werden:
>  Player otherPlayer = (Player) other;
>  } else {
>  sender.sendMessage(ChatColor.RED + args[0] + " ist gerade nicht online!");
>  }
> }
>
> ```
>

Wenn es beabsichtigt sein sollte, dass der Spieler offline ist, können natürlich auch an dem `**OfflinePlayer**` grundlegende Änderungen vorgenommen werden.
Für normale Spieler-Objekte ist es außerdem gut zu wissen, dass die `Bukkit.getPlayer(String name)` Methode nicht nach dem gesamten String sucht. Diese Methode findet zum Beispiel den Spieler *Notch*, auch wenn nur *"No"* übergeben wird. Deswegen sollte dafür `Bukkit.getPlayerExact(String exactName)` benutzt werden!

## Plugin Konfiguration und Einstellungen

*Für weiteres verwende bitte diese Seite: Introduction to the New Configuration/de*
## Berechtigungen (Permissions)

Mit der neuen Bukkit API für das Berechtigungs-System, könnte es gar nicht einfacher sein. Um herauszufinden, ob ein Spieler eine Berechtigung besitz, verwende diesen Code:

>
> ```
> if(player.hasPermission("some.pointless.permission")) {
>  // Spieler hat die Berechtigung
> }else{
>  // Spieler hat die Berechtigung nicht
> }
>
> ```
>

Zudem kannst du auch herausfinden, ob eine Berechtigung gesetzt oder nicht gesetzt wurde (gleich zu Javas **null**). Dies geht mit einer Funktion:

>
> ```
> boolean isPermissionSet(String name)
>
> ```
>

Vielleicht wunderst du dich, warum es keine Gruppen gibt. Die Antwort ist einfach: Sie werden nicht wirklich benötigt. Früher war die Hauptfunktion von Gruppen, dass die Mitglieder ein anderes Format im Chat besaßen. Das kann man jedoch auch einfach mit dem Berechtigungs-System machen:In deiner Chatplugin-Konfiguration würdest du Verknüpfungen zwischen deinen erstellten Berechtigungen und den Chat-Präfixen herstellen. Als Beispiel: "someChat.prefix.admin" würde für den Präfix [Admin] verwendet werden. Immer, wenn ein Spieler mit dieser Berechtigung etwas in den Chat schreibt, wird dieser Text vor seinem Namen stehen.

Eine weitere vorteilhafte Verwendung von einem Gruppen-System wäre das Senden einer Nachricht an alle Gruppenmitglieder einer Gruppe. Doch auch dies lässt sich mit Berechtigungen machen:

>
> ```
> for(Player player: getServer().getOnlinePlayers()) {
>  if(player.hasPermission("send.me.message")) {
>  player.sendMessage("Du bekommst eine Nachricht weil du diese Berechtigung hast.");
>  }
> }
>
> ```
>

Besser wäre allerdings eine eingebaute Funktion von Bukkit zu nutzen:

>
> ```
> getServer().broadcast("Du bekommst eine Nachricht weil du diese Berechtigung hast.", "send.me.message");
>
> ```
>

Zum Schluss fragst du dich vielleicht noch, wie man die Berechtigungen von Spielern setzen und einrichten kann, wenn es keine Gruppen gibt. Auch wenn die Bukkit API keine eigenen Gruppen mitliefert, hast du jedoch die Möglichkeit, ein Plugin für dieses Vorhaben zu verwenden. Es gibt viele Plugins für solch ein Vorhaben, zum Beispiel permissionsBukkit.

### Deine Permissions konfigurieren

Wenn du mehr Kontrolle über deine Permissions haben willst, zum Beispiel Standardwerte für untergeordnete Permissions, solltest du sie zu deinre *plugin.yml* hinzufügen. Das ist optional, wird aber empfohlen. Hier ist eine Beispiel Permissions Einstellung, die du einfach an das Ende der existierenden *plugin.yml* anhängen würdest:

> ````
> permissions:
>  pfoertner.\*:
>  description: Gibt Zugriff auf alle pfoertner Befehle
>  children:
>  pfoertner.kick: true
>  pfoertner.bann: true
>  pfoertner.klopfe: true
>  pfoertner.verboten: false
>  pfoertner.kick:
>  description: Erlaubt dir einen User zu kicken
>  default: op
>  pfoertner.bann:
>  description: Erlaubt dir ein User zu bannen
>  default: op
>  pfoertner.klopfe:
>  description: Klopft an der Tür!
>  default: true
>  pfoertner.verboten:
>  description: Verhindert, dass dieser Nutzer die Tür betritt
>
> ````
>
>

Als erstes wird jede Permission, die dein Plugin benutzt, als Unterpunkt des *permissions* Punktes hinzugefügt. Jede Permission kann optional eine Beschreibung, einen Standardwert und Unter-Permissions besitzen.

#### Standardwerte

Standardmäßig, wenn eine Permission für einen Spieler nicht gesetzt ist, wird *hasPermission* false zurückliefern. In deiner plugin.yml kannst du diese Einstellung ändern, indem du den Punkt default in einen der folgenden Werte änderst:

* **true** - Die Permission ist standardmäßig true.
* **false** - Die Permission ist standardmäßig false.
* **op** - Wenn dieser Spieler ein Operator ist, ist diese Permission standardmäßig true.
* **not op** - Wenn dieser Spieler kein Operator ist, ist diese Permission standardmäßig true.

#### Unter-Permissions

Früher wirst du vielleicht die \*-Permission genutzt haben, um alle Unter-Permissions zu setzen. Das hat sich mit der Bukkit API geändert und du kannst jetzt die Unter-Permissions festlegen. Hier ist ein Beispiel, wie du das machst:

>
> ```
> permissions:
>  pfoertner.\*:
>  description: Gibt Zugriff auf alle pfoertner Befehle
>  children:
>  pfoertner.kick: true
>  pfoertner.bann: true
>  pfoertner.klopfe: true
>  pfoertner.verboten: false
>
> ```
>

Hier hat die *pfoertner.\** Permission ein paar Unter-Permissions zugewiesen bekommen. Wenn *pfoertner.\** auf true gesetzt wird, werden die Unter-Permissions auf die in der *plugin.yml* definierten Werte gesetzt. Wenn *pfoertner.\** auf false gesetzt wird, dann wird das jeweilige Gegenteil der Unter-Permissions auf diese angewendet.

### Permissions setzen

Wenn du ein eigenes Permission-Plugin schreiben willst (Eines, das Permissions setzt), dann schau dir dieses Tutorial an Developing a permissions plugin (auf Englisch).

## Verzögerte und Hintergrund-Tasks

Aktuell arbeitet ein Minecraft-Server hauptsächlich mit einem einzigen Thread. Das bedeutet sobald es eine Verzögerung in einem Plugin oder dem Spiel an sich gibt, wirkt diese sich auf den ganzen Server aus und es gibt einen Lag. Ein rechenaufwändiger Codeabschnitt in deinem Plugin kann zu großen Verzögerung und damit zu solchen Lags führen.

Deshalb gibt es glücklicherweise in Bukkit Unterstützung für Verzögerte oder sich wiederholende Codeabschnitte. Du kannst einen Task planen, der nach einer bestimmten Zeit ausgeführt wird, einen, der regelmäßig in einem bestimmten Intervall ausgeführt wird, oder aber einen, der parallel zum Haupttask läuft und rechenintensive Prozesse ausführt.

Dafür gibt es ein Extra Scheduler Programming/de Tutorial, das zeigt, wie mit dem Bukkit Scheduler(Englisch für "Aufgabenplaner") richtig umgegangen wird.

## Blöcke verändern

Um einen Block zu erstellen oder zu bearbeiten, muss du dir als erstes das Block-Objekt an der gewünschten Position holen, und dieses verändern. Wenn du zum Beispiel den Block, der sich fünf Blöcke über dir befindet verändern willst, musst du dir als Erstes das Block-Objekt holen und kannst ihn dann verändern. Hier das Beispiel anhand eines Player-Move-Events:

>
> ```
> public void onPlayerMove(PlayerMoveEvent evt) {
>  Location loc = evt.getPlayer().getLocation();
>  World w = loc.getWorld();
>  loc.setY(loc.getY() + 5); // Gewünschte Position: 5 Blöcke über dem Spieler
>  Block b = w.getBlockAt(loc); // Ein Block-Objekt bekommt man mithilfe eines Welt-Objekts und einer Location
>  b.setType(Material.STONE);
> }
>
> ```
>

Der Code wird jedes mal wenn das Player-Move-Event ausgelöst wird einen Stein-Block fünf Blöcke über dem Spieler platzieren (Auch, wenn dort bereits ein Block ist!). Als erstes holen wir uns die Position des Spielers und als nächstes das zugehörige Welt-Objekt. Anschließend ändern wir die Position so ab, dass sie fünf Blöcke über dem Spieler liegt. Jetzt können wir uns das Block-Objekt holen. Das bekommen wir, indem wir die getBlockAt()-Methode des Welt-Objekt und die Position(Das Location-Objekt) benutzen: w.getBlockAt(loc);. Nun haben wir das Block-Objekt der gewünschten Position und können das Material oder die Block-Daten ändern. Block-Daten werden als byte angegeben und so müsstest du den Daten-Wert, den du angeben möchtest, erst in den Datentyp byte konvertieren. So könntest du zum oberen Code Folgendes hinzufügen: b.setData((byte) 3);

Mit diesen Methoden kannst du Gebäude oder andere Strukturen mithilfe von Algorithmen erstellen. Um beispielsweise eine gefüllten Würfel zu generieren, könnten wir einfach eine Methode mit drei for-Schleifen erstellen:

>
> ```
> public void generateCube(Location location, int length){ // Methode generateCube() mit zwei Paramtern location und length
>  World world = location.getWorld();
>
>  int x\_start = location.getBlockX(); // Die Start-Koordinaten bekommen wir aus der angegebenen Position
>  int y\_start = location.getBlockY(); // Man benutzt der Einfachheit halber getBlockX() anstatt getX(), weil es eine
>  int z\_start = location.getBlockZ(); // Ganzzahl zurückliefert und so nicht mehr mit (int) location.getX(); umgewandelt werden muss
>
>  int x\_length = x\_start + length; // Hier werden die End-Koordinaten mithilfe der Länge festgelegt
>  int y\_length = y\_start + length;
>  int z\_length = z\_start + length;
>
>  for(int x\_operate = x\_start; x\_operate <= x\_length; x\_operate++){
>  // 1. Schleife für die X-Dimension "for x\_operate (Bekommt den Startwert x\_start)
>  // Die Schleife führt ihren Inhalt solange aus, wie x\_operate <= x\_length
>  // Nach jedem Durchlauf wird x\_operate
>  // um 1 erhöht (x\_operate++ ist das selbe wie x\_operate = x\_operate+1;)
>  for(int y\_operate = y\_start; y\_operate <= y\_length; y\_operate++){// Zweite Schleife für die Y-Dimension
>  for(int z\_operate = z\_start; z\_operate <= z\_length; z\_operate++){// Dritte Schleife für die Z-Dimension
>  Block blockToChange = world.getBlockAt(x\_operate,y\_operate,z\_operate); // Den Block aus den 3 Koordinaten holen
>  blockToChange.setType(Material.ANVIL); // den Block ANVIL (Amboss) setzen
>  }
>  }
>  }
> }
>
> ```
>

Diese Methode erzeugt einen 3D-Würfel aus der übergebenen Seitenlänge und Startposition.

Wenn du Blöcke "löschen" möchtest, benutzt du einfach dieselbe Methode wie um sie zu setzen, aber gibst als Block Material.AIR (Luft) an.

## (Spieler) Inventar-Zugriff

Ein Inventar zu verändern wird anfänglich ein wenig schwierig aussehen. Wenn du es aber verstanden hast, wirst du sehen, dass es eigentlich recht einfach ist. In diesem Abschnitt wird hauptsächlich die beschrieben, wie man das Inventar eines Spielers bearbeitet. In anderen Inventaren funktioniert das jedoch ganz genauso, vorrausgesetzt, du hast ein Inventory-Objekt. Hier ist ein kleines Beispiel, wie man ein Spieler-Inventar bearbeiten kann:

>
> ```
> public void onPlayerJoin(PlayerJoinEvent event) {
>  Player player = event.getPlayer(); // Der Spieler
>  PlayerInventory inventory = player.getInventory(); // Das Inventar des Spielers
>  ItemStack diamondstack = new ItemStack(Material.DIAMOND, 64); // Ein Stack mit Diamanten
>
>  if (inventory.contains(diamondstack)) { //Überprüft, ob im Inventar ein Stack mit Diamanten vorhanden ist
>  inventory.addItem(diamondstack); // Fügt dem Inventar einen weiteren Stack Diamanten hinzu
>  player.sendMessage(ChatColor.GOLD + "Willkommen! Du scheinst seehr reich zu sein, deshalb hast du ein paar mehr Diamanten von uns bekommen!");
>  }
> }
>
> ```
>

Als Erstes machen wir uns drei Variablen, um uns ein wenig Schreibarbeit zu ersparen: player, inventory, diamondstack. Inventory ist das Inventar des Spielers und diamondstack ist ein 64er Stack mit Diamanten. Anschließend überprüfen wir, ob das Inventar des Spielers einen vollen Diamanten-Stack enthält. Falls ja, geben wir ihm einen weiteren Stack mithilfe von inventory.addItem(diamondstack) und schicken ihm eine goldene Chat-Nachricht. Wenn wir den bereits im Inventar vorhandenen Stack entfernen wollten, so könnten wir statt inventory.addItem(diamondstack) einfach inventory.remove(diamondstack) schreiben und die Nachricht ein wenig abändern.

## HashMaps und wie man sie benutzt

Beim programmieren eines Plugins wirst du an den Punkt kommen, an dem die Nutzung von nur einer einzigen Variable, um anzugeben, dass ein Ereignis eingetreten ist oder eine Bedingung erfüllt wurde, unzureichend ist, da mehr als ein Spieler dieses Ereignis auslöst.

Dies war das Problem, das ich mit einem meiner alten Plugins, Zones, hatte, dass jetzt verbessert und in Regions umbenannt wurde. Ich bekam die meisten Fehlermeldungen, da ich nicht bedacht hatte, wie sich das Plugin auf einem richtigen Server mit mehr als einem Spieler verhält. Ich nutzte eine einzelne Boolean Variabel, um zu überprüfen, ob sich die Spieler in der Region aufhielten oder nicht und selbstverständlich funktionierte es nicht, da die Werte für jeden Spieler anders sein mussten. Wenn sich nun also ein Spieler in der Region aufhielt und ein anderer nicht, änderte sich die Variable dauernd was zu unzähligen Fehlermeldungen führte.

Eine Hashmap ist ein ausgezeichneter Weg dieses Problem zu lösen. Eine Hashmap weist einen Wert einem Schlüssel zu. Du kannst die Hashmap so einrichten, dass der Schlüssel ein Spieler ist und der Wert eine x-beliebige Variable ist, das wirklich nützliche an einer Hashmap ist jedoch, dass ein Schlüssel nur eine Variable beinhalten kann und dass es keinen Schlüssel zweimal geben kann. Sagen wir zum Beispiel ich nehme "adam" als Schlüssel und weise ihm den Wert "a" zu. Das würde wie geplant funktionieren, aber sagen wir ich möchte danach den Wert "b" dem Schlüssel "adam" zuweisen, würde ich keine Fehlermeldungen bekommen, aber der Wert "a", der dem Schlüssel "adam" in der Hashmap zugewiesen wurde, würde überschrieben worden sein, weil Hashmaps keine doppelten Werte beinhalten können.

### Definieren einer HashMap

>
> ```
> public Map<Key, DataType> HashMapName = new HashMap<Key, Datatype>(); //Beispielhafter Syntax
>
> //Beispielhafte Deklaration
>
> public Map<Player, Boolean> pluginEnabled = new HashMap<Player, Boolean>();
> public Map<Player, Boolean> isGodMode = new HashMap<Player, Boolean>();
>
> ```
>

Merkt euch diesen Code, da wir ihn für den Rest dieses Tutorials für HashMaps benutzen werden. Lasst uns alsp als Beispiel eine einfach Funktion erstellen, die feststellt ob das Plugin aktiviert ist oder nicht. Zuerst musst du in der onCommand Funktion, die ich in dem gleichnamigen Abschnitt erklärt habe, eine Funktion erstellen, die der Funktion den Namen des Players zuschickt und den Status des Spielers dementsprechend ändert.
Also brauchst du dies innerhalb der onCommand Funktion, der Funktionsname kann anders lauten, doch aus Gründen der Einfachheit ist es das Beste wenn du ihn so lässt.

>
> ```
> Player player = (Player) sender;
> togglePluginState(player);
>
> ```
>

Der oben aufgeführte Code wird den Wert von sender in player umcasten und dieses Argument an die Funktion togglePluginState() weiterreichen. Aber nun müssen wir unsere togglePluginState() Funktion erstellen.

>
> ```
> public void togglePluginState(Player player){
>
>  if(pluginEnabled.containsKey(player)){
>  if(pluginEnabled.get(player)){
>  pluginEnabled.put(player, false);
>  player.sendMessage("Plugin disabled");
>  } else {
>  pluginEnabled.put(player, true);
>  player.sendMessage("Plugin enabled");
>  }
>  } else {
>  pluginEnabled.put(player, true); //Wenn du willst, dass dein Plugin von vorne herein aktiviert ist ändere diesen Wert zu false.
>  player.sendMessage("Plugin enabled");
>  }
>
> }
>
> ```
>

Dieser Code überprüft zuerst ob die Hashmap den Schlüssel player enthält, also ob er in die Hashmap gepackt wurde, wenn dies zutrifft überprüfen wir den Wert, der dem Schlüssel zugewiesen wurde mit get(player); wenn dies zutrifft wird der Wert auf false gesetzt und dem Spieler eine Nachricht geschickt, wenn der Wert jedoch false ist wird der Wert auf true gesetzt und dem Spieler erneut eine Nachricht geschickt. Aber wenn die Hashmap nicht den Schlüssel player enthält können wir schlussfolgern, dass der Code zum ersten Mal benutzt wird und den Standartwert ändern und den player in die Hashmap hinzufügen.

### Mehr Ideen für HashMaps

Eine HashMap (oder jede andere Art einer Map in Java) ist eine eindeutige Zuordnung. Sie erlaubt schnelles und effizientes Nachschlagen eines **Wertes (Value)**, wenn ein einzigartiger **Schlüssel (Key)**Igegeben ist. Überall, wo dies in deinem Code der Fall ist, könnte eine Map dieses Problem effizient lösen.

Hier sind noch weitere Ideen, wofür Maps besonders gut geeignet sind. Du wirst sehen, dass nicht nur Daten, welche pro Spieler gespeichert werden, in Maps genutzt werden müssen, sondern dass auch jede Art von Daten, welche von einer in eine andere Art "übersetzt" werden muss, möglich ist.

#### Data Value Lookups

>
> ```
> public Map<String, Integer> wollfarben = new HashMap<String, Integer>();
>
> // Führe dies bei Plugin-Start aus (am besten wäre es, wenn es aus einer Datei gelesen würde, statt Zeile für Zeile abgeschrieben werden zu müssen):
> wollfarben.put("orange", 1);
> wollfarben.put("magenta", 2);
> wollfarben.put("hellblau", 3);
>  ...
> wollfarben.put("schwarz", 15);
>
> // Führe dies als Antwort auf Kommandos aus - zB "grün" zu 13 umwandeln
> int datenwert = 0;
> if (wollfarben .containsKey(argument)) {
>  datenwert = wollfarben .get(argument);
> } else {
>  try { datenwert = Integer.parseInt(argument); }
>  catch (Exception e) { ; }
> }
>
> ```
>

### Speichern/Laden einer HashMap

Sobald du weißt, wie man mit HashMaps arbeitet, wirst du wahrscheinlich wissen wollen wie man die Daten einer HashMap laden und speichern kann.

Dies ist angebracht, wenn:

* du nicht willst, dass ein Administrator die Daten im Quellcode abändern muss

* wenn du sie in Binärformat speichern willst (zu komplex zu organisieren für YAML)

* wenn du vermeiden willst, Namen von Blöcken und oder anderer Objekten aus dem Eingabetext zu übersetzen

Dies ist ein ziemlich einfacher Weg jede Hashmap zu speichern. Du kannst auch "HashMap<Player,Boolean> mit jedem typen ändern, wie du möchtest. Let's continue using the "pluginEnabled" HashMap defined from the previous tutorial. This code saves the given HashMap to the file with given path.

>
> ```
> public void save(HashMap<Player,Boolean> pluginEnabled, String path)
> {
>  try{
>  ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path));
>  oos.writeObject(pluginEnabled);
>  oos.flush();
>  oos.close();
>  //Handle I/O exceptions
>  }catch(Exception e){
>  e.printStackTrace();
>  }
> }
>
> ```
>

You can see it's really easy. Loading works very very similar but we use ObjectInputStream instead of ObjectOutputStream ,FileInputStream instead of FileOutputStream,readObject() instead of writeObject() and we return the HashMap.

>
> ```
> public HashMap<Player,Boolean> load(String path) {
>  try{
>  ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));
>  Object result = ois.readObject();
>  //you can feel free to cast result to HashMap<Player,Boolean> if you know there's that HashMap in the file
>  return (HashMap<Player,Boolean>)result;
>  }catch(Exception e){
>  e.printStackTrace();
>  }
> }
>
> ```
>

You can use this "API" for saving/loading HashMaps, ArrayLists, Blocks, Players... and all Objects you know ;) . Please credit me (Tomsik68) if you use this in your plugin.

>
> ```
> /\*\* SLAPI = Saving/Loading API
>  \* API for Saving and Loading Objects.
>  \* @author Tomsik68
>  \*/
> public class SLAPI
> {
>  public static void save(Object obj,String path) throws Exception
>  {
>  ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path));
>  oos.writeObject(obj);
>  oos.flush();
>  oos.close();
>  }
>  public static Object load(String path) throws Exception
>  {
>  ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));
>  Object result = ois.readObject();
>  ois.close();
>  return result;
>  }
> }
>
> ```
>

Example implementation of this API: **I'm skipping some part of code in this source**

>
> ```
> public class Example extends JavaPlugin {
>  private ArrayList<Object> list = new ArrayList<Object>();
>  public void onEnable()
>  {
>  list = (ArrayList<Object>)SLAPI.load("example.bin");
>  }
>  public void onDisable()
>  {
>  SLAPI.save(list,"example.bin");
>  }
> }
>
> ```
>

A minor note about this SLAPI and Java's ObjectOutputStream class. This will work un-modified if you are saving almost all well-known Java types like Integer, String, HashMap. This will work un-modified for some Bukkit types as well. If you're writing your own data object classes, and you may want to save their state using this technique, you should read up on Java's Serializable interface. It's easy to add to your code, and it will make your data persistent with very little work on your part. No more parsing!

## Maps, and Sets, and Lists, Oh My!

Besides the Map/HashMap classes, Java offers many other data structures. They offer these different classes because there are times when a Map is not the most appropriate. Here's a separate page for discussing Java data structure classes in more detail.

## Databases

Sometimes flat files aren't enough for what your looking to do, this is where databases come in. The most common database engines available on Linux/Mac/Windows machines typically run on some flavor of SQL (Structured Query Language).

Software offering SQL allow you to create databases with columns and header to identify to contents of each cell. Think of it as a spreadsheet on steroids, where every column you set up in your database can enforce rules to ensure integrity. Apart from being more organised than a simple custom data file, SQL provides faster access and better searching than flat files.

The SQL standard helps applications like Bukkit implement database storage for their data in a consistent way. Unfortunately, there's more than one SQL-ready database engine, and each has minor differences in how to configure and use it. Which one you choose may depend on your particular needs. (Some plugins even offer configurable options to connect to multiple database engines!)

### SQLite

Alta189 has written a fantastic SQLite tutorial which I suggest you watch if you're interested in using SQL in your plugins, included with the tutorials is a handy library you can download and import to make using SQL easier. Once you have watched these video tutorials I would suggest you go and learn some SQL syntax, it's very straightforward and shouldn't take you long to pick up. SQL Tutorials @W3Schools

SQLite is great for very simple databases, because there's no server concerns to set up. Just make a few calls to create a new database and table. It's easy to back up: just copy the whole database file in one go. SQLite is a little bit weaker at data integrity, flexibility in data types, and it may not be something you would want to trust for huge databases of millions of rows. But for a new plugin in development, it's often easiest and fastest to get the SQL basics squared away with SQLite, even if you "graduate" to a more server-class database engine later.

### MySQL

Another popular SQL database engine is called MySQL. It is closer to server-grade than SQLite, where many popular companies or websites depend on it for millions of webpage hits every day. With that security comes a little bit steeper learning-curve, because MySQL has more tunable parameters and capabilities.

The coding for plugins accessing MySQL is mostly the same as tiny SQLite or mega-sized Oracle, with only small differences in syntax here or there. But the administration has room to grow. You may want to set up accounts and privileges inside your MySQL setup. You may want to set up SQL scripts that organize your backups and rollback to previous states.

## Bereitstellen des Plugins

Nachdem du mit dem schreiben deines Plugins fertig bist, fragst du dich bestimmt wie du dieses zu einer funktionierenden JAR-File machst. Als erstes erstellst du dir einen Bukkitserver auf deinem Computer. Wie dies funktioniert findest du auf der Server ertsellen Seite. Als nächstes musst du dein Plugin zu einer .jar machen, so dass du es auf deinem Server installieren kannst. Um das in Eclipse zu machen, klicke auf File > Export. In dem sich öfnenden Fenster, unter "Java", wähle "JAR file", und klicke auf next. Du wirst ein Fenster sehen welches wie dieses aussieht:

Versichere dich das auf der Linken Seite der src Ordner ausgewählt ist. Au der rechten Seite siehst du zwei Dateien welche mit einem Dezimalpunkt beginnen, diese gehören zu Eclipse and are not important to your plugin, so deselect them. It is vital that plugin.yml is selected in order for your plugin to work. Export your JAR file to any destination you like, but make sure you know where it is.

The jar file you have exported should now be a working plugin! Assuming of course that there are no errors in your code or your plugin.yml file. You can now drop the jar file you have exported into your bukkit server's "plugins" folder, reload or relaunch the server, and test away! In order to connect to a server running locally on your computer, simply put "localhost" as the IP address of the server in Minecraft multiplayer. If you run into errors that you can't solve for yourself, try visiting the plugin development forum, asking in the bukkitdev IRC channel, or re-reading this wiki. Once you have a useful working plugin, consider submitting your project to dev.bukkit for consumption by the Bukkit community.

## Tipps und Tricks

Die CraftBukkit API kann eine Menge coole Dinge machen. Es folgen einige Beispiele.

### Einen Spieler anzünden

So könnte man einen Befehl, der einen Spieler in Band setzt, implementieren.

>
> ```
> public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args){
>  if(cmd.getName().equalsIgnoreCase("ignite")){
>  Player s = (Player)sender;
>  Player target = s.getWorld().getPlayer(args[0]); // Hier wird der Spieler, der angezündet werden soll, gefunden
>  // Beispiel: Wenn "/ignite notch" eingegeben wurde, wird der Spieler "notch" ausgewählt.
>  // Beachte: Das erste Argument ist [0], nicht [1]. Also wird der Spieler im arg[0] ausgewählt.
>  target.setFireTicks(10000);
>  return true;
>  }
>  return false;
> }
>
> ```
>

Wenn nun jemand "/ignite notch" eingibt, wird Notch, falls er online ist, in Brand gesetzt

### Einen Spieler töten

Auf diese Weise tötet man einen Spieler. Dabei ist es egal, ob sich der Spieler im Survival-, Kreativ- oder Adventure-Modus befindet.

Dafür wird dieser Codeabschnitt in deine onCommand() eingesetzt:

>
> ```
> public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args){
>  if(cmd.getName().equalsIgnoreCase("KillPlayer")){
>  Player player = (Player)sender;
>  Player target = player.getWorld().getPlayer(args[0]);
>  target.setHealth(0);
>  }
>  return false;
> }
>
> ```
>

Eine Erweiterung dafür (Der Spieler stirbt in einer Explosion):

>
> ```
> float explosionPower = 4F; //Wie stark soll die Explosion sein? TNT hat eine Stärke von 4F
> Player target = sender.getWorld().getPlayer(args[0]);
> target.getWorld().createExplosion(target.getLocation(), explosionPower);
> target.setHealth(0);
>
> ```
>

### Explosion erstellen

Dieser Code erzeugt visuelle Effekte sowie Geräusche einer Explosion.

>
> ```
>  public void onExplosionPrime(ExplosionPrimeEvent event){
>
>  Entity entity = event.getEntity();
>
>  if (entity instanceof TNTPrimed){
>  TNTPrimed tnt = (TNTPrimed) entity;
>  event.getEntity().getWorld().createExplosion(tnt.getLocation(), 0);
>
>  }
>  }
>
> ```
>

## Request Section

### HowTo: make plugin using maven

Using git, clone the BukkitPluginArchetype repo and build the archetype:

>
> ```
> git clone git://github.com/keyz182/BukkitPluginArchetype.git
> cd BukkitPluginArchetype
> mvn clean install
>
> ```
>

Now, in the folder you want to create the plugin in, run the following commands:

>
> ```
> mvn archetype:generate -DarchetypeCatalog=local
>
> ```
>

then select the following from the list when prompted:

> uk.co.dbyz:bukkitplugin (bukkitplugin)
>
>

For groupid, enter what you'd use as the first part of the Java Package.For Artifactid, enter the last part of the package. Accept Version and package as is, then type Y <enter>

E.G.:

>
> ```
> Define value for property 'groupId': : uk.co.dbyz.mc
> Define value for property 'artifactId': : plugin
> Define value for property 'version': 1.0-SNAPSHOT:
> Define value for property 'package': uk.co.dbyz.mc:
>
> ```
>

You'll now have a folder named as whatever you used for archetypeid. In that folder is a folder, src, and a file, pom.xml.

Open the <archetypeid>CommandExecuter.java file in src/main/java/<package>, and add the following code where it says //Do Something

>
> ```
> Player player = (Player) sender;
> player.setHealth(1000);
>
> ```
>

Now, go back to the base folder and run

>
> ```
> mvn package
>
> ```
>

It may take a while downloading things, but let it do it's thing. When done, there'll be a folder called target, and a file called <archetypeid>-1.0-SNAPSHOT.jar inside it. Copy this file to the bukkit server plugin folder and reload the server.

Now, if you type the command /<archetypeid in minecraft while logged into the server, it'll give you full health!

## Example Files and Templates

* Example.Java

* ExamplePlayerListener.Java

* ExampleBlockListener.Java

* ExampleEntityListener.Java

If you have any more questions on this matter, don't hesitate to contact Adamki11s or anyone on the BukkitDev IRC Channel

For further editing or german related questions please contact tr4st here or here.