br.com.blackhubos.eventozero.factory.Event.java Source code

Java tutorial

Introduction

Here is the source code for br.com.blackhubos.eventozero.factory.Event.java

Source

/**
 *
 * EventoZero - Advanced event factory and executor for Bukkit and Spigot.
 * Copyright  2016 BlackHub OS and contributors.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 */
package br.com.blackhubos.eventozero.factory;

import java.lang.reflect.InvocationTargetException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Random;
import java.util.Vector;

import org.apache.commons.lang.NullArgumentException;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.Sign;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;

import br.com.blackhubos.eventozero.EventoZero;
import br.com.blackhubos.eventozero.ability.Ability;
import br.com.blackhubos.eventozero.kit.Kit;
import br.com.blackhubos.eventozero.party.Party;
import br.com.blackhubos.eventozero.rewards.ChestReward;
import br.com.blackhubos.eventozero.storage.Storage;
import br.com.blackhubos.eventozero.util.Framework;
import br.com.blackhubos.eventozero.util.Framework.*;
import java.util.HashMap;
import java.util.Map;

/**
 * TODO: arrumar index do setSign (todos 0) TODO: adicionar logs
 * (getLoggerService()) nos backups e afins para deixar registrado TODO:
 * adicionar as mensagens e seus replaces aos respectivos voids necessrios
 * TODO: documentar (javadoc) todos os mtodos e construtores em Portugus BR.
 *
 * Falta algo? documente aqui com um TODO: mensagem TODO = To Do (a fazer) TODO:
 * no modo espectador, desativar comandos exceto do eventozero
 */
public class Event {

    private final String name;
    private final EventData data;

    private final List<Player> joineds;
    private final List<Player> spectators;
    private final List<Party> partys;
    private final List<Ability> abilitys;
    private final List<Cuboid> cuboids;
    private final List<Location> locations;
    private final Map<String, Location> camarotes;

    private String displayName;
    private String description;
    private EventState state;
    private EventFlags flags;
    private EventPlacements placements;
    private EventAnnouncement announcement;
    private Configuration config;

    public Event(final String name) {
        this.flags = new EventFlags();
        this.name = name;
        this.joineds = new Vector<>();
        this.spectators = new Vector<>();
        this.partys = new Vector<>();
        this.abilitys = new Vector<>();
        this.data = new EventData();
        this.cuboids = new Vector<>();
        this.locations = new Vector<>();
        this.camarotes = new HashMap<>();
        this.announcement = new EventAnnouncement(this, 10, 10);
    }

    public Event(final String name, final Configuration config) {
        this(name);
        this.config = config;
    }

    /**
     *
     * @return Retorna o nome do evento de forma como configurado (em casos
     * importantes use lower-case!)
     */
    public String getName() {
        return this.name;
    }

    public EventFlags getFlags() {
        return this.flags;
    }

    /**
     *
     * @return Retorna a lista de cuboids definidos neste evento.
     */
    public List<Cuboid> getCuboids() {
        return this.cuboids;
    }

    /**
     *
     * @return Retorna a descrio do evento.
     */
    public String getDescription() {
        return this.description;
    }

    /**
     *
     * @return Retorna o nome customizado do evento.
     */
    public String getDisplayName() {
        return this.displayName;
    }

    /**
     * @return {@link Integer} Retorna minimo de player permitido no evento para
     * iniciar
     */
    public int getMin() {
        return this.getData().getData("options.player_min");
    }

    /**
     * @return {@link Integer} Retorna maxmimo de player permitido no evento.
     */
    public int getMax() {
        return this.getData().getData("options.player_max");
    }

    /**
     *
     * @return Retorna o {@link EventData} do evento, que contm vrias
     * informaes.
     */
    public EventData getData() {
        return this.data;
    }

    /**
     * Os eventos tem vrios estados, com este mtodo,  possvel identificar o
     * estado atual do evento. Leia mais na classe EventState.
     *
     * @return Retorna o estado do evento.
     */
    public EventState getState() {
        return this.state;
    }

    /**
     *
     * @return {@link EventAnnouncement} retorna o Anuncio do evento
     */
    public EventAnnouncement getAnnouncement() {
        return this.announcement;
    }

    /**
     *
     * @return Retorna {@link Ability} fixada no evento, no caso todos
     * participantes teriam esta habilidade
     */
    public Ability getFixedAbility() {
        return getData().getData("options.ability.fixed_ability");
    }

    /**
     * Atualiza a descrio do evento
     *
     * @param desc Nova descrio
     * @return Retorna a instncia do {@link Event} modificada.
     */
    public Event updateDescription(final String desc) {
        this.description = desc;
        return this;
    }

    /**
     *
     * @param displayname
     * @return Retorna a instncia do {@link Event} modificada.
     */
    public Event updateDisplayName(final String displayname) {
        this.displayName = displayname;
        return this;
    }

    public Configuration getConfig() {
        return this.config;
    }

    /**
     *
     * @return Retorna a lista de todas as partys em ao do evento.
     */
    public List<Party> getPartys() {
        return this.partys;
    }

    /**
     *
     * @return Retorna a lista de todos os participantes do evento.
     */
    public List<Player> getPlayers() {
        return this.joineds;
    }

    /**
     *
     * @return Retorna a lista de todos os jogadores restantes no evento.
     */
    public Vector<Player> getPlayersRemaining() {
        return getPlayers().stream().filter(spec -> !getSpectators().contains(spec)).collect(Vector::new,
                Vector::add, Vector::addAll);
    }

    /**
     *
     * @return Retorna a lista de todos os es espectadores ativos no evento.
     */
    public List<Player> getSpectators() {
        return this.spectators;
    }

    /**
     *
     * @return Retorna as habilidades (Abilitys) do evento.
     */
    public List<Ability> getAbilitys() {
        return this.abilitys;
    }

    public List<Location> getSignsLocation() {
        return this.getData().getData("options.signs.locations");
    }

    /**
     *
     * @return Retorna lista de entradas do camarote
     */
    public List<Location> getEntradas() {
        return locations;
    }

    /**
     *
     * @param index
     * @return Retorna entrada
     */
    public Location getEntrada(int index) {
        return this.locations.get(index);
    }

    /**
     *
     * @param name
     * @return Location do camarote definido pelo parametro name
     */
    public Location getCamaroteByName(String name) {
        return this.camarotes.get(name);
    }

    /**
     *
     * @return Retorna todos camarote
     */
    public Map<String, Location> getCamarotes() {
        return this.camarotes;
    }

    /**
     * 
     * @return {@link EventPlacements}
     */
    public EventPlacements getPlacements() {
        return this.placements;
    }

    /**
     *
     * @param player
     * @return
     */
    public Event playerJoin(final Player player) {
        if ((player == null) || !player.isOnline())
            throw new NullArgumentException("Player is null");
        if (!this.hasPlayerJoined(player)) {
            this.joineds.add(player);
            this.updateSigns();

            if (safeInventory()) {
                this.playerBackup(player);
                player.getInventory().clear();
                player.getInventory().setArmorContents(new ItemStack[4]);
            }

            final Location teleportTo = getRandomTeleport("lobby");
            if (teleportTo != null)
                player.teleport(teleportTo);
            else
                EventoZero.consoleMessage("O teleporte (lobby) do evento (" + getName() + ") esta nulo.");
        }
        return this;
    }

    /**
     *
     * @param player
     * @return
     */
    public Event playerQuit(final Player player) {
        if ((player == null) || !player.isOnline())
            throw new NullArgumentException("Player is null");
        if (this.hasPlayerJoined(player)) {
            this.joineds.remove(player);
            this.spectatorQuit(player);
            this.updateSigns();
            if (safeInventory())
                this.playerRestore(player);
        }
        return this;
    }

    /**
     * Define um jogador como espectador. TODO: (o jogador deveria ser
     * teleportado para o lugar do evento por aqui ou pelo comando?)
     *
     * @param player Jogador em questo a virar espectador
     * @return Retorna a instncia do {@link Event} modificada.
     */
    public Event spectatorJoin(final Player player) {
        if ((player == null) || !player.isOnline())
            throw new NullArgumentException("Player is null");
        if (!this.spectators.contains(player)) {
            getPlayers().forEach(p -> p.hidePlayer(player));
            player.setAllowFlight(true);
            player.setFlying(true);
            this.spectators.add(player);
        }
        return this;
    }

    /**
     * Remove um jogador do modo espectador.
     *
     * @param player Jogador que ser removido do modo espectador.
     * @return Retorna a instncia do {@link Event} modificada.
     */
    public Event spectatorQuit(final Player player) {
        if ((player == null) || player.isOnline())
            throw new NullArgumentException("Player is null");
        if (this.spectators.contains(player)) {
            for (final Player obj : this.getPlayers()) {
                obj.showPlayer(player);
            }
            player.setAllowFlight(false);
            player.setFlying(false);
            this.spectators.remove(player);
        }
        return this;
    }

    /**
     *
     * @param player
     * @return {@code true} se o jagodor j entrou no evento.
     */
    public boolean hasPlayerJoined(final Player player) {
        return this.joineds.contains(player);
    }

    /**
     *
     * @return True se protege o inventrio
     */
    public boolean safeInventory() {
        return this.getData().getData("options.enables.safe_inventory");
    }

    /**
     *
     * @return {@code true} se as party esto ativado
     */
    public boolean enablePartys() {
        return this.getData().getData("options.enables.party");
    }

    /**
     *
     * @param location
     */
    public void addEntrada(Location location) {
        this.locations.add(location);
    }

    /**
     *
     * @param name
     * @param location
     */
    public void setCamarote(String name, Location location) {
        this.camarotes.put(name, location);
    }

    /**
     *
     */
    public void stop() {
        // TODO: STOP EVENT, GET WINNERS, ALIVES
        this.forceStop();
        this.updateSigns();
    }

    public void start() {
        if (this.getState() == EventState.CLOSED) {
            EventoZero.startAnnouncementHandler();
            this.updateState(EventState.OPENED);
            this.updateSigns();
        }
    }

    public void forceStop() {
        // TODO: STOP FORCE EVENT
        for (final Player player : this.joineds) {
            this.playerQuit(player);
        }
        updateState(EventState.CLOSED);
        if (EventoZero.getEventHandler().getEventsSizeClosed() == 0)
            EventoZero.closeAnnouncementHandler();
        this.updateSigns();
    }

    public void forceStart() {
        // TODO: START EVENT
        if (this.getPlayers().size() < this.getData().<Integer>getData("event.min"))
            // TODO: STOP
            // TODO: MESSAGE CANCELED MIN PLAYER
            this.forceStop();

        final EventData data = this.getData();

        this.getPlayers().forEach(player -> {
            final Kit kit = data.getData(player.getName() + ".kit");

            if (kit != null) {
                kit.giveTo(player);
                if (kit.hasAbility())
                    data.updateData(player.getName() + ".ability", kit.getAbility());
            }
            //TODO: getRandomTeleport pode retornar nulo, temos que tratar caso acontea
            player.teleport(getRandomTeleport("spawn"));
        });

        this.updateState(EventState.OCCURRING);

        // TODO: CODE START
        this.updateSigns();
    }

    /**
     * Este mtodo ir criar um backup no banco de dados do EventoZero com dados
     * importantes sobre o jogador, tais como, vida, comida, itens, xp,
     * localizao, armadura, etc. Voc poder restaurar esse backup ao jogador
     * quando quiser, pois fica salvo em backup. Note que os backups no so
     * retirados do banco de dados aps restaurar, so apenas 'trancados' e no
     * podem mais ser usados.
     *
     * @param player O jogador que dever ter um novo backup criado para o
     * evento em questo.
     */
    public void playerBackup(final Player player) {
        this.getData().updateData(player.getName() + ".inventory.contents", player.getInventory().getContents());
        this.getData().updateData(player.getName() + ".inventory.armorContents",
                player.getInventory().getArmorContents());
        this.getData().updateData(player.getName() + ".ability",
                this.getData().getData("options.ability.fixed_ability"));
        EventoZero.getStorage().backupPlayer(player, this.name.toLowerCase());
    }

    /**
     * Este mtodo ir restaurar um backup do jogador, salvo no banco de dados
     * do EventoZero com dados importantes sobre o jogador, tais como, vida,
     * comida, itens, xp, localizao, armadura, etc. Voc poder restaurar esse
     * backup ao jogador quando quiser, pois fica salvo em backup. Note que os
     * backups no so retirados do banco de dados aps restaurar, so apenas
     * 'trancados' e no podem mais ser usados.
     *
     * @param player
     */
    public void playerRestore(final Player player) {
        if ((player == null) || ((player != null) && !player.isOnline()))
            throw new NullArgumentException("Player is null");
        final ResultSet rs = EventoZero.getStorage()
                .search("SELECT * FROM `" + Storage.Module.BACKUP.getTable() + "` WHERE `jogador`='"
                        + player.getName().toLowerCase() + "' AND `devolvido`='0' AND `evento`='"
                        + this.name.toLowerCase() + "';");
        try {
            if (rs.next()) {
                // TODO: isso  para ter compatibilidade de 1.5.2 (health por int) e 1.7+ (health por double)
                try {
                    player.getClass().getMethod("setHealth", double.class).invoke(player,
                            (double) rs.getInt("vida"));
                } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException
                        | SecurityException e1) {
                    try {
                        player.getClass().getMethod("setHealth", int.class).invoke(player, rs.getInt("vida"));
                    } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException
                            | SecurityException e2) {
                    }
                }
                player.setFoodLevel(rs.getInt("comida"));
                player.setExp(rs.getFloat("xp"));
                player.setLevel(rs.getInt("level"));
                player.teleport(Framework.toLocation(rs.getString("localizacao")));
                player.getInventory().setContents(
                        (ItemStack[]) this.getData().getData(player.getName() + ".inventory.contents"));
                player.getInventory().setArmorContents(
                        (ItemStack[]) this.getData().getData(player.getName() + ".inventory.armorContents"));
                this.getData().removeKeyStartWith(player.getName());
            }
        } catch (IllegalArgumentException | SQLException e) {
            e.printStackTrace();
        }

    }

    /**
     * Atualiza o status do evento
     *
     * @param state
     * @return
     */
    public Event updateState(EventState state) {
        this.state = state;
        return this;
    }

    public Event updateEventPlacements(EventPlacements eventPlacements) {
        this.placements = placements;
        return this;
    }

    /**
     * Atualiza todas placas
     */
    public void updateSigns() {
        if (this.getData().containsKey("options.signs.locations")
                && (this.getData().getData("options.signs.locations") != null)) {
            final Vector<Location> signs = (Vector<Location>) getSignsLocation();
            for (final Location location : signs) {
                final Block block = location.getWorld().getBlockAt(location);
                if ((block.getType() == Material.SIGN_POST) || (block.getType() == Material.WALL_SIGN)) {
                    final String string = String
                            .valueOf(this.getData().getData("options.message." + this.getState().getPath()));
                    final Sign sign = (Sign) block.getState();
                    sign.setLine(0, String.valueOf(this.getData().getData("options.signs.line.1"))
                            .replace("{state]", string)
                            .replace("{playersize}", String.valueOf(this.getPlayers().size()))
                            .replace("{playermax}", String.valueOf(this.getData().getData("options.player_max")))
                            .replace("{name}", this.getName()).replaceAll("&", ""));
                    sign.setLine(1, String.valueOf(this.getData().getData("options.signs.line.2"))
                            .replace("{state]", string)
                            .replace("{playersize}", String.valueOf(this.getPlayers().size()))
                            .replace("{playermax}", String.valueOf(this.getData().getData("options.player_max")))
                            .replace("{name}", this.getName()).replaceAll("&", ""));
                    sign.setLine(2, String.valueOf(this.getData().getData("options.signs.line.3"))
                            .replace("{state]", string)
                            .replace("{playersize}", String.valueOf(this.getPlayers().size()))
                            .replace("{playermax}", String.valueOf(this.getData().getData("options.player_max")))
                            .replace("{name}", this.getName()).replaceAll("&", ""));
                    sign.setLine(3, String.valueOf(this.getData().getData("options.signs.line.4"))
                            .replace("{state]", string)
                            .replace("{playersize}", String.valueOf(this.getPlayers().size()))
                            .replace("{playermax}", String.valueOf(this.getData().getData("options.player_max")))
                            .replace("{name}", this.getName()).replaceAll("&", ""));
                    sign.update();
                } else
                    // remove a locaiton da sign
                    signs.remove(location);
            }
        }
    }

    /**
     * Pega um teleporte aleatorio de uma lista de teleportes.
     *
     * @param teleport Nome do teleport, por exemplo {@code lobby} ou
     * {@code spawn}
     * @return Uma localizao caso encontre, null caso no existe a key
     * 'teleport.{@code teleport}' nos {@link #getData() dados} do evento, ou o
     * numero de Locations seja 0
     */
    private Location getRandomTeleport(final String teleport) {
        final Random random = new Random();
        final EventData data = getData();

        if (!data.containsKey("teleport." + teleport))
            return null;

        final List<Location> locations = getData().getData("teleport." + teleport);
        if (locations.isEmpty())
            return null;

        return locations.get(random.nextInt(locations.size()));
    }
}