Plugin Tutorial/es

## Introducción

Este gran tutorial pretende comenzar con el desarrollo de un plugin en Bukkit. Es imposible hacer un tutorial completo de todas las posibilidades de creación de un plugin en Bukkit, pero prefiero un resumen general de los conceptos básicos. Comience por asegurarse de que usted entiende Java, configurar su espacio de trabajo en un IDE presenta los elementos esenciales de la mayoría de plugins Bukkit.

## Aprender Java

Estos tutoriales requieren conocimientos básicos del lenguaje de programación Java. Si acaba de empezar con Java o necesita un repaso, échele un vistazo a los siguientes links, le ayudarán enormemente! (Están en Inglés).

Los tutoriales de Oracle le ayudarán a entender el lenguaje de Java:

* Java2s.com - Prácticamente todo lo posible en Java aquí
* Java 101 - Tutoriales
* JavaNotes - Tutorial - texto bajo licencia.

### Videotutoriales JAVA

Los siguientes videotutoriales están en Inglés

* iTechRemix Instrucciones básicas por iTechRemix
* Thenewboston - Un montón de vídeos increíbles
* JavaVideoTutes.com - Videotutoriales IMPORTANTES.

## El entorno de desarrollo

Antes de desarrollar un plugin (o aprendizaje de Java), usted necesitará configurar un entorno de desarrollo. Esto incluye pero no se limita a instalar un IDE (Integrated Development Environment). El siguiente tutorial contiene instrucciones para el IDE de Eclipse.

 *Para más información, vea Setting Up Your Workspace*
## Comenzando con el proyecto del plugin

### Creando el Proyecto

Antes de empezar, usted necesitará configurar su espacio de trabajo y archivos en Eclipse.
Inicie Eclipse, luego crear un nuevo proyecto seleccionando *File > New > Java Project:*

Nombrar al proyecto como usted quiera, luego ejecute el asistente de proyecto nuevo, siguiendo las instrucciones en pantalla. Una carpeta aparecerán en el panel explorador de paquete en el lado izquierdo; "izquierdo" en la pequeña flecha al lado de él para mostrar el contenido de su proyecto.

### Referencia de la API de Bukkit

Antes de empezar a desarrollar tu plugin, usted necesitará agregar la biblioteca de la API de bukkit a su proyecto como un JAR externo. También puede añadir cualquier otra API que desea utilizar.

La ultima versión de la API de Bukkit puede descargarla de aquí: Bukkit API - Development Snapshot

Haga clic derecho sobre la carpeta con el nombre de su proyecto en el panel Package Explorer en el lado izquierdo de la pantalla y seleccione  *Properties* . Luego seleccione  *Java Build Path* en la caja de opciones a la izquierda. Haga clic en  *Add External JARs* y navegue hasta donde descargaste la API de Bukkit.

### Javadocs de Bukkit

Si usted tiene alguna experiencia con Eclipse y Java usted sabrá que cuando se pasa el ratón por encima de cualquier clase o método una caja amarilla aparecerá, conteniendo la documentación de esa clase o método. Esto se conoce como un Javadoc y también se puede acceder en línea desde Oracle website. Bukkit también tiene documentación que a menudo contiene descripciones útiles de cada método y clase proporcionada por la API, que está disponible aquí.
Para tener esta información disponible dentro de Eclipse, primero haga clic derecho en el nombre del proyecto, luego haga click en  *Propiedades*, luego en  *Javadoc Location* y en el cuadro de texto que aparece escribir **http://jd.bukkit.org/apidocs/**. Debe quedar así:

Haga clic en Validate y, a continuación, haga clic en Aceptar. ¡Ya está! Ahora los Javadocs de Bukkit están vinculados a la fuente Bukkit, y se puede acceder a la documentación útil desde dentro de Eclipse.

### Creando un paquete

Ahora lo que necesita para crear un "paquete" que almacenará todos los archivos de clase Java que vamos a utilizar. Haga clic derecho sobre la carpeta "src" y seleccione *New > Package*

Nombre su paquete de la siguiente manera:

* Si usted tiene un nombre de dominio, el paquete sería el nombre de dominio a la inversa.
	+ Ejemplo: Si su dominio es: i-am-a-bukkit-developer.com Su paquete sería: com.i\_am\_a\_bukkit\_developer Fuente
	+ Evite el uso de un dominio que no es suyo.
* No tiene dominio? ¡Tienes otras opciones!
	1. Cree una cuenta en un sitio de control de código fuente, como github o SourceForge.
		+ Para github, siga las instrucciones aquí y tendrá un sub-dominio, por lo que el paquete sería io.github.<nombredeusuario>
	2. Use su correo electrónico. Ejemplo: <nombredeusuario>@gmail.com sería com.gmail.<nombredeusuario>
	3. Este es el metodo menos recomendado... Solo tiene que utilizar cualquier nombre de paquete, una vez más, utilice esto como su último recurso.

Hay varias cosas que el paquete debe **NO** empezar:

* org.bukkit
* net.bukkit
* com.bukkit
* net.minecraft

Una vez que tenga el nombre del paquete base, tendrá que acabar con él con el nombre del plugin. Vamos a utilizar las páginas de ejemplo, github, para esto. Si va a crear un plugin llamado "TestPlugin" el nombre completo del paquete sería "io.github.<nombredeusuario>.Testplugin".

### Creando la clase del plugin

Ahora que ya tenemos nuestro proyecto creado, podemos empezar a añadir archivos de clases y comenzar a hacer nuestro plugin. La clase principal del plugin es la clase que extiende el plugin de Java. Siempre debe haber una clase en tu plugin que extiende el plugin de Java directa o indirectamente. Siempre es una buena práctica para crear su primera clase principal y darle el mismo nombre que su plugin. Haga click derecho en el paquete que creó anteriormente y seleccione *New > Class*.
Usted debe tener una nueva clase similar a la siguiente:

>
> ```
> package {$TopLevelDomain}.{$Domain}.{$PluginName};
>
> import org.bukkit.plugin.java.JavaPlugin;
>
> public final class {$PluginName} extends JavaPlugin {
>
> }
>
> ```
>

### Creando plugin.yml

Ahora que ha configurado el proyecto y la clase principal debe permitir que bukkit cargue el Plugin. Para eso debe crear el archivo **plugin.yml**. Este archivo contendrá la información esencial, y sin el, el plugin, no funcionará.
Esta vez haremos click derecho en la carpeta raiz (La carpeta que tiene el mismo nombre que nuestro proyecto)
Hacemos click derecho y presionamos *New > File*. En el cuadro de texto llamado File Name ingresamos "**plugin.yml**" Y luego Finish.
Eclipse abrirá nuestro archivo nuevo automáticamente en el editor de texto predeterminado.

**Pista:** Si quieres mantener tu espacio de trabajo organizado, debe cerrar el editor de texto y arrastrar **plugin.yml**  a la principal área de trabajo (a la derecha) y será capaz de editar el archivo dentro de eclipse.

Hay tres atributos esenciales que deben ser declarados en el plugin.yml:

name: El nombre de su Plugin
main: NOMBRE COMPLETO de la clase principal de su Plugin
version: La versión del Plugin
El archivo **plugin.yml** tendrá este aspecto:

>
> ```
> name: {$PluginName}
> main: {$PackageName}.{$MainClass}
> version: {$VersionNumber}
>
> ```
>

 **Note**: El nombre del paquete de plugins a menudo incluye el nombre del plugin, por lo que no se sorprenda de ver pluginname.pluginname al final de la segunda línea.
 **Note**: Tu clase principal puede o no puede ser el nombre de su plugin en función de lo que usted nombró antes, ten en cuenta que distingue entre mayúsculas y minúsculas.
En este momento tu plugin puede ser cargado por Bukkit y se acompañará con las entradas del registro que indica esto, pero no hará nada!

## onEnable() y onDisable()

Estos métodos se llaman cada vez que el plugin se habilita y deshabilita. De manera predeterminada su plugin va a permitir, de forma automática, hacer algo. Puede registrar los acontecimientos y proporcionar un cierto resultado de la depuración aquí. `onEnable()` se ejecuta cuando el plugin está habilitado, y debe contener la lógica para configurar el plug-in cuando está activado. `onDisable()` se ejecuta cuando un plugin está deshabilitado y debe contener la lógica para limpiar el lector y el estado asociado. Además, el plugin, puede reemplazar el `onLoad()` para realizar lógica adicional cuando se carga el plugin.

### Introducción a onEnable() y onDisable()

Primero que nada debemos hacer los métodos `onEnable()` y `onDisable()` dentro de la clase principal creada en la sección anterior. Con esto podremos habilitar y deshabilitar nuestro plugin.
Se debería ver como en las lineas siguientes:

>
> ```
> package {$TopLevelDomain}.{$Domain}.{$PluginName};
>
> import org.bukkit.plugin.java.JavaPlugin;
>
> public final class {$PluginName} extends JavaPlugin {
>
>  @Override
>  public void onEnable() {
>  // Insertar aquí la lógica para llevar a cabo cuando el plugin está habilitado.
>  }
>
>  @Override
>  public void onDisable() {
>  // Insertar aquí la lógica para llevar a cabo cuando el plugin está deshabilitado.
>  }
>
> }
>
> ```
>

Los métodos que existen ahora hacen que nuestro plugin pueda habilitarse y deshabilitarse cuando el servidor sea iniciado, reiniciado o apagado.
Nota: El hacer una impresión que diga "{$PluginName} se ha habilitado!" no servirá de nada. Bukkit hará esto automáticamente.

### Registrar un mensaje

Un plugin puede imprimir un mensaje en la consola y en el registro del servidor. Esto puede lograr invocando el método correcto de registrador del plugin. Primero debemos ejecutar el método `getLogger()` para recuperar el registrador asociado con este plugin. Entonces podemos empezar el registro.
Vamos a escribir en el registro cuando se llama al método `onEnable()`. Podemos hacerlo insertando la siguiente línea en el método `onEnable()`.

>
> ```
> getLogger().info("onEnable se ejecuto correctamente!");
>
> ```
>

A continuación, puede hacer lo mismo en el interior de `**onDisable()**`, por lo que asegúrese de cambiar el mensaje.

Ahora, su clase principal, debe parecerse a esto:

>
> ```
> package {$TopLevelDomain}.{$Domain}.{$PluginName};
>
> import org.bukkit.plugin.java.JavaPlugin;
>
> public final class {$PluginName} extends JavaPlugin {
>
>  public void onEnable(){
>  getLogger().info("onEnable se ejecuto correctamente!");
>  }
>
>  public void onDisable(){
>  getLogger().info("onDisable se ejecuto correctamente!");
>  }
> }
>
> ```
>

### Manejo del comando /reload

Es importante recordar que esto no sólo ocurre en el arranque y apagado del servidor, tu plugin también puede ser deshabilitado y habilitado por otros plugins o a través del uso del comando /reload mientras se ejecuta el servidor. Asumiendo que el servidor se ha iniciado sólo cuando está activado el plugin es, por lo tanto, una peligrosa suposición, como bien ya puede haber cargado de mundos de jugadores en línea, adicional, trozos adicionales cargados y muchas otras diferencias inesperadas.

Por ejemplo:

* Tienes un plugin que almacena información sobre un jugador en un HashMap en el PlayerJoinEvent
* Usted confía en tener esa información disponible para cada jugador.
* Un operador utiliza el comando /reload.
* Tu plugin se desactiva y todos los datos almacenados se pierde.
* Tu plugin se activa nuevamente con varios jugadores ya online.
* Estos jugadores no tienen ninguna información almacenada para ellos en el HashMap.
* Intenta recuperar información sobre ellos, pero no hay ninguno!

Para que funcione correctamente en la recarga, debes encontrar a todos los jugadores actualmente en línea durante onEnable y almacenar la información correcta para ese jugador en el HashMap.

## "Oyentes"

Los oyentes son clases cuyos métodos son invocados en respuesta a un evento. Todos los oyentes implementan org.bukkit.event.Listener.
Para obtener más información sobre la creación de los oyentes,

 *vea por favor: Event API Reference*
## Comandos

### El método onCommand()

Así que ahora sabes cómo registrar eventos y hacer algo cuando suceden, pero ¿y si sólo quieres algo que pasará cuando se escribe un comando? Utilizas `**onCommand**`. Este código se ejecuta cada vez que un jugador tipos un comando precedido por el carácter "/". Por ejemplo escribiendo "/hola" llamaría el método `**onCommand**`. En este caso nada sucedería porque el comportamiento no ha sido programado.

Evite el uso de comandos que son las mismas que las que vienen con Bukkit. Por ejemplo el comando "/give" es utilizado ya por varios plugins, y si se implementa otro comando "/give", tu plugin será incompatible con esos otros plugins. Usted debe registrar sus comandos en plugin.yml del plugin o no se accionarán este método.

El método `**onCommand**` siempre debe devolver un valor booleano (true / false). Si el valor devuelto es verdadero no verás ningún evento notable. Sin embargo si devuelve false entonces el plugin volverá a tus archivos plugin 'usage: property' y mostrar un mensaje al usuario mostrando cómo usar el comando como se especifica en el **plugin.yml** archivo.

Cuando se usa `**onCommand**`, usted siempre debe registrar 4 parámetros.

* `**CommandSender sender**` - ¿Quien envió el comando?

* `**Command cmd**` - ¿El comando se ejecutó?

* `**String commandLabel**` - El alias del comando que se ejecutó

* `**String[] args**` - un array de argumentos adicionales, por ejemplo escribiendo /hola abc def pondría abc en args [0] y def en args [1]

### Configurar el comando

>
> ```
> public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args){
>  if(cmd.getName().equalsIgnoreCase("basic")){ //Si el jugador ha escrito /basic entonces haga lo siguiente...
>  // Hacer algo...
>  return true;
>  } //Si pasó la función devolverá true.
>  // Si esto ha sucedido la función devolverá el valor false.
>  return false;
> }
>
> ```
>

Al codificar la función `**onCommand**` siempre es recomendable que devuelva false al final de la función. Al devolver false se mostrará el diálogo de uso establecido en **plugin.yml** (ver más abajo). Si algo sale mal se mostrará el mensaje de ayuda esta manera. Al devolver un valor de la función se cerrará por lo que si usted vuelve true debajo de cualquier código no se ejecutará, a menos que está anidada una sentencia return en una sentencia if o similar.

El `**.equalsIgnoreCase("basic")**` sólo significa que no va a distinguir entre caracteres mayúsculas y minúsculas. Por ejemplo, la cadena "Básico" y "básico" lo interpreta como lo mismo.

### Agregar un comando a Plugin.yml

Usted también deberá agregar el comando a su archivo **plugin.yml**. Agregue lo siguiente al final del **plugin.yml**:

> ````
>  description: Este es un comando de ejemplo.
>  usage: /<command> [player]
>  permission: <nombredelplugin>.basico
>  permission-message: Usted no tiene <permiso>
>
> ````
>
>

* `**basico**` - Nombre del comando.

* `**description**` - Descripción del comando.

* `**usage**` - El diálogo de ayuda que los usuarios verán cuando regrese falso en el `**onCommand**`. Escribir con claridad, para que otros puedan discernir lo que el comando es y cómo usarlo.

* `**permission**` - Esto es utilizado por algunos plugins de ayuda para resolver los comandos para mostrar al usuario.

* `**permission-message**` - Este es el mensaje cuando el jugador intenta pero no tiene permiso para utilizar el mando.

Tenga en cuenta que los archivos yml utilizan 2 espacios para las pestañas, ya que el carácter de tabulación causará problemas.

### Comandos de consola vs. Comandos del jugador

Usted puede haber notado el parámetro anterior `**CommandSender sender**`. `**CommandSender**` es una interfaz de Bukkit que tiene dos subclases útilidades (para los escritores de plugin) `**Player**` y `**ConsoleCommandSender**`.

Cuando usted está escribiendo su plugin, es una muy buena idea asegurarse de que los comandos que *puede* ejecutar desde la consola realmente funcionan, y que los comandos que sólo se deben ejecutar como un jugador registrado en verdad *NO* se pueden usar desde consola. Algunos plugins simplemente devuelven si el remitente no es un jugador (es decir, alguien trató de utilizar los comandos del plugin desde la consola), aunque estos comandos tienen sentido desde la consola (por ejemplo, el cambio del clima en el servidor).

Una forma de hacer esto es:

>
> ```
> public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
>  if (cmd.getName().equalsIgnoreCase("basico")){ //Si el jugador ha escrito /basico entonces haga lo siguiente...
>  // Hacer algo...
>  return true;
>  } else if (cmd.getName().equalsIgnoreCase("basico2")) {
>  if (!(sender instanceof Player)) {
>  sender.sendMessage("Este comando sólo puede ser ejecutado por un jugador.");
>  } else {
>  Player player = (Player) sender;
>  // Hacer algo...
>  }
>  return true;
>  }
>  return false;
> }
>
> ```
>

En este ejemplo, el comando **basico** puede ser ejecutado por cualquier persona. Sin embargo, el comando **basico2** sólo puede ser dirigido por los jugadores.

En general, se debe permitir que tantos comandos como sea posible para trabajar en la consola y para los jugadores. Los comandos que necesitan los jugadores pueden utilizar el mecanismo en el ejemplo anterior para comprobar que el `**CommandSender**` es en realidad un jugador antes de continuar. Tales comandos serían generalmente dependerá de algún atributo del jugador, por ejemplo, un comando de teletransporte necesita un jugador para teletransportarse, un elemento que da comando necesita un jugador para dar el artículo a ...

Si usted quiere estar más avanzado, podrías hacer algunas comprobaciones adicionales en sus argumentos de comando para que, por ejemplo, un comando de teleportación podría utilizarse desde la consola *if and only if* también se suministra el nombre de un jugador.

### Usando una clase aparte de CommandExecutor

Los ejemplos anteriores sólo puso el método `**onCommand()**` en la clase principal del plugin. Para pequeños plugins, esto está bien, pero si escribes algo más extenso, tal vez tenga que poner su método `**onCommand()**` en su propia clase. Afortunadamente, esto no es demasiado difícil:

* Crear una nueva clase dentro del paquete de su plugin. Llamarlo algo como **MiPluginCommandExecutor** (aunque por supuesto reemplazar **MiPlugin** con el nombre real de su plugin). Esa clase  *debe*  implementar la interfaz Bukkit **CommandExecutor**

* En el método `**onEnable()**` de tu plugin , necesitas crear una instancia de su nueva clase de comando ejecutor y luego realizar una llamada como `getCommand("basico").setExecutor(myExecutor);` donde basico es el comando que queremos manejar, y `myExecutor` es la instancia que creamos.

Expliquemoslo con un ejemplo:

**MyPlugin.java** (La clase principal del Plugin):

>
> ```
> @Override
> public void onEnable() {
>  // ...
>
>  // Esto producirá un NullPointerException si no tienes el comando definido en el archivo plugin.yml.
>  getCommand("basico").setExecutor(new MiPluginCommandExecutor(this));
>
>  // ...
> }
>
> ```
>

**MiPluginCommandExecutor.java**:

>
> ```
> public class MiPluginCommandExecutor implements CommandExecutor {
>
>  private MiPlugin plugin; // Puntero a la clase principal, no se requiere si no necesitas los métodos de la clase principal
>
>  public MiPluginCommandExecutor(MiPlugin plugin) {
>  this.plugin = plugin;
>  }
>
>  @Override
>  public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
>  // implementación exactamente igual que antes...
>  }
> }
>
> ```
>

Observe cómo pasamos una instancia del plugin principal al constructor para **MyPluginCommandExecutor**. Esto nos permite fácil acceso a los métodos de la principal del plugin si es necesario.

Al hacer esto, podemos organizar mejor nuestro código - si el principal `**onCommand()**` es grande y complejo, se puede dividir en submétodos sin abarrotar la clase principal del plugin.

Tenga en cuenta que si su plugin tiene varios comandos, tendrá que establecer el ejecutor de comandos para cada comando individual.

### Escribiendo un onCommand seguro

Al escribir un onCommand, es importante que no comprometa la información, tales como el remitente de ser un jugador. Cosas a tener en cuenta:

#### Asegúrese de que el remitente es un jugador antes de emitir

Utilizando un simple código así lo hace posible:

>
> ```
> public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args){
>  if (sender instanceof Player) {
>  Player player = (Player) sender;
>  // Hacer algo...
>  } else {
>  sender.sendMessage("Usted debe ser un jugador!");
>  return false;
>  }
>  // Hacer algo...
>  return false;
> }
>
> ```
>

#### Compruebe la longitud de los argumentos

No asumas siempre que el remitente escribió la cantidad correcta de argumentos!!

>
> ```
> public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args){
>  if (args.length > 4) {
>  sender.sendMessage("Demasiados argumentos!");
>  return false;
>  }
>  if (args.length < 2) {
>  sender.sendMessage("No hay suficientes argumentos!");
>  return false;
>  }
> }
>
> ```
>

#### Al nombrar otro jugador por su nombre, asegúrese de que está en línea

A veces usted quiere conseguir otro jugador por el nombre introducido por el jugador. Asegúrese siempre de que el jugador está en línea!

>
> ```
> public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args){
>  Player target = (Bukkit.getServer().getPlayer(args[0]));
>  if (target == null) {
>  sender.sendMessage(args[0] + " no se encuentra online!");
>  return false;
>  }
>  return false;
> }
>
> ```
>

Si necesitas modificar un jugador actualmente qué no está en línea, la clase `**OfflinePlayer**` proporciona los métodos de manipulación básica.

## Configuración del plugin

El API Bukkit proporciona una manera conveniente a los plugins gestionar los ajustes configurables por el usuario. Además también sirve como una manera fácil de almacenar datos.

*Please see: Configuration API Reference*
## Permisos

Con la nueva API de Bukkit para permisos, no podría ser más fácil. Para averiguar si un jugador tiene un permiso especial utilice lo siguiente:

>
> ```
> if(player.hasPermission("some.pointless.permission")) {
>  //Hacer algo
> }else{
>  //Hacer otra cosa
> }
>
> ```
>

También puedes consultar si un permiso se ha establecido o no (En Java llamado **nulo**) con la siguiente función:

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

Te preguntarás por qué no hay ningún grupo. La respuesta es porque ellos no son realmente necesarios. Previamente uno de los principales usos de los grupos fue dar formato a los mensajes de chat. Sin embargo puede hacerse fácilmente con los permisos. Dentro de la configuración del plugin de tu chat definiría asociaciones entre permisos y prefijos. Por ejemplo, el permiso "someChat.prefix.admin" se correspondería con el prefijo [Admin]. Cuando un jugador habla con ese permiso su nombre llevará el prefijo con [Admin].

Otro uso común sería enviar un mensaje a todos los usuarios dentro de un grupo. Otra vez sin embargo esto se puede hacer con permisos con lo siguiente:

>
> ```
> for(Player player: getServer().getOnlinePlayers()) {
>
>  if(player.hasPermission("send.receive.message")) {
>  player.sendMessage("Te enviaron un mensaje!!");
>  }
>
> }
>
> ```
>

Finalmente usted puede decir, bueno ¿cómo establecer y organizar los permisos del jugador si hay ningún grupo? Aunque la API de bukkit no proporciona grupos de sí mismo, debe instalar un plugin de proveedor de permiso como permissionsBukkit, groupmanager, etc. Para administrar los grupos para ti. **Este API proporciona la interfaz, no la implementación.**

### Configuración de los permisos

Si desea más control sobre los permisos, por ejemplo, los valores por defecto o "hijos", entonces debería considerar añadir a su *plugin.yml*. Esto es completamente opcional, sin embargo se aconseja. A continuación se muestra un ejemplo de configuración de permisos que se añade al final de su actual *plugin.yml*:

> ````
> permissions:
>  portero.\*:
>  description: Acceso a todos los comandos de portero
>  Hijo:
>  portero.kick: true
>  portero.ban: true
>  portero.knock: true
>  portero.denied: false
>  doorman.kick:
>  description: Permite expulsar a un usuario.
>  default: op
>  doorman.ban:
>  description: Permite banear a un usuario.
>  default: op
>  doorman.knock:
>  description: Llama a la puerta!
>  default: true
>  doorman.denied:
>  description: Evita este usuario entre en la puerta
>
> ````

En primer lugar, cada permiso que tu plugin utiliza se define como un nodo secundario del nodo *permisos*. Cada permiso luego opcionalmente puede tener hijos, una descripción y un valor predeterminado.

#### Predeterminados

Por defecto, cuando un permiso no está definido para un jugador *hasPermission* devolverá false. Dentro de su plugin.yml puede cambiarse esta configuración del nodo predeterminado a ser uno de los cuatro valores:

* **true** - El permiso será true de forma predeterminada. (Permitido).
* **false** - El permiso será false de forma predeterminada. (NO permitido).
* **op** - Si el jugador es OP entonces será true. (Permitido si es OP).
* **not op** - Si el jugador no es OP entonces será true. (NO permitido si es OP).

#### "Hijos"

Antes de ahora es probable que se utilizará el \* permiso para asignar automáticamente todos los sub-permisos. Esto ha cambiado con la API de bukkit y ahora puede definir los permisos secundarios. Esto permite mucha más flexibilidad. A continuación se muestra un ejemplo de cómo hacerlo:

>
> ```
> permissions:
>  portero.\*:
>  description: Acceso a TODOS los comandos de portero
>  hijo:
>  portero.kick: true
>  portero.ban: true
>  portero.knock: true
>  portero.denied: false
>
> ```
>

Aquí el permiso de *portero.\** tiene varios permisos secundarios, o "hijos", que le asignamos. La manera que trabajan los permisos hijos es cuando *portero.\** se establece en true, el niño permisos se establecen en sus valores definidos en el *plugin.yml*. Sin embargo, si  *portero.\** fue establecida en false podría invertirse todos los permisos de "hijo".

### Establecer sus propios permisos

Si desea saber sobre el desarrollo de tus propios plugins de permisos, revisá el tutorial en Developing a permissions plugin.

## Programación de tareas y tareas de fondo

Actualmente, los servidores de Minecraft operan casi toda la lógica del juego en un hilo, por lo que cada tarea individual que ocurre en el juego tiene que ser muy breves. Una pieza complicada de código en su plugin tiene el potencial de causar grandes retrasos y de retardo para los picos de la lógica del juego (Tambien llamado lagg), si no se maneja correctamente.

Por suerte, Bukkit tiene soporte para programar el código en tu plugin. Usted puede presentar una tarea ejecutable para ocurrir una vez en el futuro, o en forma recurrente, o usted puede girar en un subproceso independiente nuevo que puede realizar tareas largas en paralelo con la lógica del juego.

Hay un tutorial separado Scheduler Programming que introduce al programador y da más información sobre usarlo para programar tareas síncronas y dando inicio a las tareas asincrónicas en Bukkit.

## Manipulación de bloques

La forma más fácil de crear bloques es modificar un bloque existente. Por ejemplo, si desea cambiar el bloque que está ubicado a cinco bloques arriba, primero tendrías tu ubicación actual, agregar cinco a la coordenada actual, y luego cambiar. Por ejemplo:

>
> ```
> public void onPlayerMove(PlayerMoveEvent event) {
>  // Obtener la ubicación del jugador
>  Location loc = event.getPlayer().getLocation();
>  // Loc se establece en cinco bloques anteriores donde solía estar. Tenga en cuenta que esto no cambia la posición del jugador.
>  loc.setY(loc.getY() + 5);
>  World w = loc.getWorld();
>  // Obtiene el bloque en la nueva ubicación.
>  Block b = w.getBlockAt(loc);
>  // Establece el bloque con ID 1 (Piedra)
>  b.setTypeId(1);
> }
>
> ```
>

El código anterior obtiene la ubicación del jugador, luego obtiene cinco bloques por encima de él y lo establece en piedra.
Nota: Una vez que tienes un `bloque`, hay otras cosas que puedes hacer además de establecer su tipo. Para más información, consulte los JavaDocs.

Puede utilizar un concepto similar para generar edificios y bloques individuales mediante programación, mediante el uso de algoritmos. Por ejemplo, para generar un cubo sólido, podría utilizar bucles anidados `for` sobre un cubo entero y rellenarlo.

>
> ```
> public void Generarcubo(Location loc, int length){
>  // Coloca una esquina del cubo en la ubicación indicada.
>  // Utiliza getBlockN() en lugar de getN() para evitar la proyección de un entero más tarde.
>  int x1 = loc.getBlockX();
>  int y1 = loc.getBlockY();
>  int z1 = loc.getBlockZ();
>
>  // Averiguar la esquina opuesta del cubo de la esquina y agregar longitud a todas las coordenadas.
>  int x2 = x1 + length;
>  int y2 = y1 + length;
>  int z2 = z1 + length;
>
>  World world = loc.getWorld();
>
>  // Loop en el cubo en la dimensión x.
>  for (int xPoint = x1; xPoint <= x2; xPoint++) {
>  //Loop en el cubo en la dimensión y.
>  for (int yPoint = y1; yPoint <= y2; yPoint++) {
>  // Loop en el cubo en la dimensión z.
>  for (int zPoint = z1; zPoint <= z2; zPoint++) {
>  // Obtener el bloque que estamos por Recorrer.
>  Block currentBlock = world.getBlockAt(xPoint, yPoint, zPoint);
>  // Establece el bloque de tipo 57 (bloque de diamante).
>  currentBlock.setTypeId(57);
>  }
>  }
>  }
> }
>
> ```
>

Este método se construirá un cubo 3D o cuboides con la longitud dada y punto de partida. En cuanto a eliminar bloques simplemente seguir el mismo método para crearlas pero la ID se establece en 0 (aire).

## Manipulación de inventario

Esta sección cubre sobre todo manipulación de inventario de jugador, pero lo mismo se aplica a la manipulación de inventario de cofres, si descubres cómo hacer inventario de un cofre :P. Aquí un simple ejemplo de manipulación de inventario:

>
> ```
> public void onPlayerJoin(PlayerJoinEvent evt) {
>  Player player = evt.getPlayer(); // El jugador que se unió
>  PlayerInventory inventory = player.getInventory(); // El inventorio del jugador
>  ItemStack itemstack = new ItemStack(Material.DIAMOND, 64); // Un stack de diamantes
>
>  if (inventory.contains(itemstack)) {
>  inventory.addItem(itemstack); // Agregar el stack.
>  player.sendMessage("Bienvenido! Se le agrego un stack de diamantes!");
>  }
> }
>
> ```
>

Así que dentro de onPlayerJoin primero hacemos unas pocas variables para hacer nuestro trabajo más fácil: player, inventory y itemstack. El inventory es el inventario del jugador y itemstack es un ItemStack que tiene 64 diamantes. Después de eso, comprobamos si el inventario del jugador contiene un stack de diamantes. Si el jugador tiene un stack de diamantes, le damos otro stack con inventory.addItem(itemstack) y enviamos un mensaje. Manipular un inventario no es en realidad tan difícil, si queríamos podíamos quitar la pila de diamantes, simplemente cambiando inventory.addItem (itemstack) con inventory.remove (itemstack) y cambiar el mensaje un poco.

## Manipulación de items

Tratándose de artículos en el código, se utiliza la clase ItemStack para buscar y configurar toda la información en esa pila.

### Encantamientos

Para encantar a un elemento primero debes saber el [código de artículo http://www.minecraftwiki.net/wiki/Data\_values] y el efecto ID. Los encantamientos mismos no pueden crear instancias (new Enchantment() no funciona) porque son abstractos, por lo que debe utilizar un EnchantmentWrapper. No se puede encantar objetos que normalmente no son encantables en SMP porque los servidores Bukkit no están configurados para enviar información de encantamientos de artículos no encantables. Así que no hay palos de fuego.

```
int itemCode = 280; //utilizar el ID del artículo que usted quiere aquí.
int effectId = 20; //utilizar el ID de encanto que usted quiere aquí.
int enchantmentLevel = 100; //Colocar el nivel de encantamiento aquí.

ItemStack myItem = new ItemStack(itemCode); //Llamamos a la variable que trae el ID del ITEM
Enchantment myEnchantment = new EnchantmentWrapper(effectId); //Llamamos a la variable que trae el ID del ENCANTAMIENTO
myItem.addEnchantment(myEnchantment, enchantmentLevel); //Encantar item...

```

## Metadatos

Bukkit está intentando hacer lo más fácil posible, desarrollo del plugin y HashMaps con clave de tipo de jugador, entidad, mundo o incluso un bloque fueron reemplazados por metadatos. Metadatos están una especie de alternativa a HashMap. Permite agregar los "campos" personalizados a los jugadores, Entidades, mundos y Bloques.

### ¿Por qué utilizar Metadatos?

Metadatos es todo manejado por Bukkit, lo que la hace muy buena alternativa a HashMaps.

Los Metadatos pueden utilizarse para compartir información entre plugins.

### ¿Por qué no utilizar metadatos?

-Un poco más difícil para obtener el valor.
-No se guarda al apagar.

### Consiguiendo & configurando metadatos

```
/\* If you're having these methods in your plugin's main class (which extends JavaPlugin), you can remove parameters plugin from them, and in the FixedMetadataValue constructor and getMetadata method, use "this" instead\*/
public void setMetadata(Player player, String key, Object value, Plugin plugin){
 player.setMetadata(key,new FixedMetadataValue(plugin,value));
}
public Object getMetadata(Player player, String key, Plugin plugin){
 List<MetadataValue> values = player.getMetadata(key);
 for(MetadataValue value : values){
 if(value.getOwningPlugin().getDescription().getName().equals(plugin.getDescription().getName())){
 return value.value();
 }
 }
}

```

Nota: Si va a manipular con números, booleanos o cadenas, utilice el método conveniente para obtener el resultado. Por ejemplo, puede utilizar asInt, AsString o asBoolean en lugar del valor de averiguar el valor.

## Bases de datos

Archivos planos a veces no son suficiente para lo que buscas hacer, Acá es cuando entran las bases de datos. Los motores de base de datos más comunes disponibles en máquinas Linux/Mac/Windows normalmente es SQL.

El software SQL permite crear bases de datos con columnas y rúbrica para identificar al contenido de cada celda. Considéralo como una hoja de cálculo con esteroides, donde todas las columnas definidas en su base de datos pueden aplicar reglas para asegurar la integridad. Además de ser más organizado que un archivo de datos personalizado simple, SQL proporciona un acceso más rápido y mejor ámbito de archivos planos.

### MySQL

Otro motor de base de datos SQL popular se llama MySQL. Es más cercano al servidor-grado que SQLite, donde muchas empresas populares o sitios web depende de él para millones de visitas de la página web cada día. Con seguridad viene un poco más empinada curva de aprendizaje, porque MySQL tiene más parámetros regulables y capacidades.

La codificación para plugins acceder a MySQL sobre todo es lo mismo que tiny SQLite o mega-sized Oracle, con sólo pequeñas diferencias en la sintaxis de aquí o allá. Pero la administración tiene espacio para crecer. Quizá quieras configurar cuentas y privilegios dentro de la configuración de MySQL. Quizá quieras configurar scripts SQL que organizan tus backups y rollback a Estados anteriores.

## Implementar el Plugin

Una vez que haya escrito el plugin, ¿cómo conseguir que a partir de una colección de archivos de código fuente en un archivo jar de trabajo que se puede instalar en un servidor? En primer lugar, establecer un servidor CraftBukkit en su máquina local. Para ello, visite la página wiki en Configurar un servidor. A continuación, tiene que exportar su plugin en un archivo. Jar de manera que se puede ejecutar en el nuevo servidor. Para ello, en Eclipse, haga clic en File > Export. En la ventana que aparece, en "Java", seleccione "JAR file" y haga clic en siguiente. Usted verá una ventana parecida a esta:

A la izquierda, asegúrese de que está seleccionada la carpeta src. A la derecha, los dos archivos que comienzan con un punto decimal tienen que ver con Eclipse y no son importantes para su plugin, puede anular la selección. Es vital que plugin.yml se seleccione para que su plugin pueda trabajar. Exportar el archivo JAR a cualquier destino que quiera, pero asegúrese de que sabe dónde está.

El archivo jar que ha exportado ahora debe ser un trabajo plugin! asumiendo por supuesto que no hay ningún error en el código o el archivo plugin.yml. Ahora puede soltar el archivo jar ha exportado en la carpeta "plugins" de su servidor bukkit, volver a cargar o reiniciar el servidor, y probar de distancia! Para conectarse a un servidor que ejecuta localmente en el equipo, en pocas palabras "localhost" como la dirección IP del servidor de Minecraft multijugador. Si se encuentra con errores que no se puede resolver por sí mismo, trate de visitar el Foro de desarrollo de plugin, pregunta en la bukkitdev canal IRC o volver a leer este wiki. Una vez que tenga un plugin útil de trabajo, la posibilidad de presentar su proyecto de dev.bukkit para el consumo de la comunidad Bukkit.

## Consejos y trucos

### Prendiendo a un jugador fuego

La API de CraftBukkit es capaz de muchas cosas interesantes. Aquí están algunos fragmentos de código para algunos efectos agradables!

El siguiente código permite a un jugador que prendió fuego a otro jugador. Ejecutar un comando como **/ignite Notch** causaría la muesca que se prendió fuego.

```
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
 // Utiliza equalsIgnoreCase() sobre equals() para aceptar "encender" y "IgNiTe".
 if (cmd.getName().equalsIgnoreCase("ignite")) {
 // Asegúrese de que el jugador especificado exactamente un argumento (el nombre del jugador para encender).
 if (args.length != 1) {
 // Cuando onCommand() devuelve false, se muestra el mensaje de ayuda asociado con ese comando.
 return false;
 }

 // Asegúrese de que el remitente es un jugador.
 if (!(sender instanceof Player)) {
 sender.sendMessage("Sólo los jugadores pueden prender fuego con otros jugadores.");
 sender.sendMessage("Este es un requisito arbitrario sólo con fines de demostración.");
 return true;
 }

 // Conseguir el jugador que debe establecerse en fuego. Recuerda que indecies empezar con 0, no 1.
 Player target = Bukkit.getServer().getPlayer(args[0]);

 // Asegúrese de que el jugador esté en línea.
 if (target == null) {
 sender.sendMessage(args[0] + " no esta conectado!");
 return true;
 }

 // Establece el jugador en el fuego de 1000 ticks (hay ~ 20 ticks en el segundo, por lo que 50 segundos en total).
 target.setFireTicks(1000);
 return true;
 }
 return false;
}

```

### Matar el jugador

Para seguir con el tema, aquí es una manera de matar el jugador.

Use esto para su método onCommand:

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

Aquí es una extensión, que matará al jugador con una explosión:

>
> ```
> float explosionPower = 4F; //Este es el poder de explosión - explosiones de TNT son 4F por defecto
> Player target = sender.getWorld().getPlayer(args[0]);
> target.getWorld().createExplosion(target.getLocation(), explosionPower);
> target.setHealth(0);
>
> ```
>

### Creando una explosión falsa

Este código produce los efectos de TNT/Creeper Visual y de Audio. Sin embargo, no hay daños de explosión se reparten a entidades o bloques. Esto es útil para desmejoras explosiones mientras se mantiene la estética de ellos.

>
> ```
> @EventHandler
> public void onExplosionPrime(ExplosionPrimeEvent event) {
>  Entity entity = event.getEntity();
>
>  // Si el evento se cebó sobre TNT (TNT que está a punto de explotar), a continuación, haga algo
>  if (entity instanceof TNTPrimed) {
>  entity.getWorld().createExplosion(entity.getLocation(), 0);
>  }
> }
>
> ```
>

### Esconde un jugador de otro jugador

Esto ocultará el jugador que ha usado este comando de un jugador especificado. Todo el mundo será capaz de ver el reproductor.

```
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
 if(cmd.getName().equalsIgnoreCase("HideMe") && args.length == 1) {
 if (!(sender instanceof Player)) {
 sender.sendMessage("Sólo los jugadores pueden usar este comando!");
 return true;
 }
 // Después de comprobar para asegurarse de que el remitente es un jugador que, con seguridad nos podemos caso a uno.
 Player s = (Player) sender;

 // Obtiene el jugador que no debería ver el remitente.
 Player target = Bukkit.getServer().getPlayer(args[0]);
 if (target == null) {
 sender.sendMessage("Player " + args[0] + " is not online.");
 return true;
 }
 // Esconde un jugador determinado (s) de alguien (blanco).
 target.hidePlayer(s);
 return true;
 }
 return false;
}

```

### Generar rayo donde está mirando el jugador

El código siguiente permite que cualquier jugador con una caña de pescar cree un rayo pulsando (y apuntando a algún lugar). Es un truco simple y divertido.

```
@EventHandler
public void onPlayerInteractBlock(PlayerInteractEvent event) {
 Player player = event.getPlayer();

 if (player.getItemInHand().getTypeId() == Material.FISHING\_ROD.getId()) {
 // Crea un rayo de luz en un lugar determinado. En este caso, ese lugar es donde se ve el jugador.
 // Sólo se puede crear un rayo encima a 200 bloques.
 player.getWorld().strikeLightning(player.getTargetBlock(null, 200).getLocation());
 }
}

```

## Solicitar sección

http://forums.bukkit.org/forums/plugin-requests.13/

## Archivos de ejemplo y plantillas

* Bukkit/SamplePlugin en Github

* Example.Java

* ExamplePlayerListener.Java

* ExampleBlockListener.Java

* ExampleEntityListener.Java

Si tienes más preguntas sobre este tema, no dude en visitar el canal de BukkitDev IRC y pedir!