net.tbnr.util.player.TPlayer.java Source code

Java tutorial

Introduction

Here is the source code for net.tbnr.util.player.TPlayer.java

Source

/*
 * Copyright (c) 2014.
 * CogzMC LLC USA
 * All Right reserved
 *
 * This software is the confidential and proprietary information of Cogz Development, LLC.
 * ("Confidential Information").
 * You shall not disclose such Confidential Information and shall use it only in accordance
 * with the terms of the license agreement you entered into with Cogz LLC.
 */

package net.tbnr.util.player;

import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import lombok.extern.java.Log;
import net.tbnr.gearz.Gearz;
import net.tbnr.gearz.packets.wrapper.WrapperPlayServerWorldParticles;
import net.tbnr.util.IPUtils;
import net.tbnr.util.RandomUtils;
import net.tbnr.util.RedFactory;
import net.tbnr.util.TPlugin;
import org.bson.types.ObjectId;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.scoreboard.DisplaySlot;
import org.bukkit.scoreboard.Objective;
import org.bukkit.scoreboard.Score;
import org.bukkit.scoreboard.Scoreboard;
import org.bukkit.util.Vector;

import java.lang.reflect.Field;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.UUID;

import static net.tbnr.gearz.packets.wrapper.WrapperPlayServerWorldParticles.ParticleEffect;

/**
 * {@link net.tbnr.util.player.TPlayer} is a representation of the {@link org.bukkit.entity.Player} in {@link org.bukkit.Bukkit} that can store more data about the {@link net.tbnr.util.player.TPlayer}, and also execute methods
 * on the player that are considered "helper" methods. These methods are utilities to preform very simple tasks that would
 * otherwise be more difficult using the vanilla Bukkit API.
 */
@SuppressWarnings("UnusedDeclaration")
@EqualsAndHashCode(of = { "playerName", "timeJoined", "uuid" }, doNotUseGetters = true)
@ToString(of = { "playerName", "timeJoined" }, includeFieldNames = true, doNotUseGetters = true)
@Log
public final class TPlayer {
    /**
     * The variable storing the actual {@link org.bukkit.entity.Player} this represents. R/O
     */
    @Getter
    private final String playerName;

    @Getter
    private final String uuid;
    /**
     * The database document representing the {@link org.bukkit.entity.Player}.
     */
    @Getter
    private DBObject playerDocument;
    /**
     * The time the {@link org.bukkit.entity.Player} joined.
     */
    @Getter
    private final long timeJoined;
    /**
     * The time the {@link org.bukkit.entity.Player} has spent online.
     */
    private long timeOnline;
    /**
     * A boolean representing that a {@link org.bukkit.entity.Player} has joined for the first time.
     */
    @Getter
    private boolean firstJoin;
    /**
     * Scoreboard object for the {@link org.bukkit.entity.Player}
     */
    private Scoreboard scoreboard;
    /**
     * Objective for {@link org.bukkit.entity.Player} on sidebar
     */
    private Objective sidebar = null;

    /**
     * This is a protected method for creating a {@link net.tbnr.util.player.TPlayer} instance from a {@link org.bukkit.Bukkit} {@link org.bukkit.entity.Player}.
     *
     * @param player The {@link org.bukkit.Bukkit} {@link org.bukkit.entity.Player} this represents.
     */
    protected TPlayer(Player player) {
        this.playerName = player.getName();
        this.uuid = player.getUniqueId().toString();
        this.timeJoined = Calendar.getInstance().getTimeInMillis();

        this.scoreboard = Bukkit.getScoreboardManager().getNewScoreboard();

        if (TPlayerManager.getInstance().getCollection() == null)
            return;

        this.playerDocument = TPlayer.getPlayerObject(player.getUniqueId());
        if (this.playerDocument == null) {
            this.playerDocument = new BasicDBObject("uuid", player.getUniqueId().toString()); //So we didn't find it, create our own, and set the username var.
            this.playerDocument.put("time-online", 0l); //Sets the online time to 0 so this var is present (long).
            this.playerDocument.put("first-join", Calendar.getInstance().getTimeInMillis());
            this.firstJoin = true;
        } else {
            this.firstJoin = false;
        }
        if (this.playerDocument.get("first-join") == null) {
            this.playerDocument.put("first-join", Calendar.getInstance().getTimeInMillis());
        }
        this.playerDocument.put("last-seen", Calendar.getInstance().getTimeInMillis()); //Update last-seen
        this.playerDocument.put("online", true); //Update the online variable
        addToList("usernames", this.playerName);

        this.save();
        this.timeOnline = (Long) this.playerDocument.get("time-online");
    }

    private void addToList(String fieldName, String toAdd) {
        BasicDBList field = (BasicDBList) this.playerDocument.get(fieldName);
        if (field == null) {
            field = new BasicDBList();
        }
        if (!field.contains(toAdd)) {
            field.add(toAdd);
        }
        this.playerDocument.put(fieldName, field);
    }

    public void logIp(String ip) {
        if (ip == null)
            return;
        addToList("ips", ip);
        this.save();
    }

    public static DBObject getPlayerObject(UUID uuid) {
        return getPlayerObject(uuid.toString());
    }

    public static DBObject getPlayerObject(String uuid) {
        BasicDBObject query = new BasicDBObject("uuid", uuid); //Query the database for the player's UUID
        DBCursor cursor = TPlayerManager.getInstance().getCollection().find(query);
        if (cursor.hasNext()) {
            return cursor.next();
        } else {
            return null;
        }
    }

    public static DBObject getPlayerObjectByLastKnownName(String name) {
        BasicDBObject query = new BasicDBObject("current_username", name); //Query the database for the player's last known username
        return TPlayerManager.getInstance().getCollection().findOne(query);
    }

    public static DBObject getAnyPlayerWithUUID(String uuid) {
        BasicDBObject query = new BasicDBObject("uuid", uuid);
        return TPlayerManager.getInstance().getCollection().findOne(query);
    }

    public static DBObject getPlayerByObjectId(String objectId) {
        ObjectId created = new ObjectId(objectId);
        BasicDBObject query = new BasicDBObject("_id", created);
        return TPlayerManager.getInstance().getCollection().findOne(query);
    }

    /**
     * Get the actual {@link org.bukkit.entity.Player} this object represents
     *
     * @return The player object from Bukkit that this represents
     */
    public Player getPlayer() {
        Gearz.getInstance().debug("GEARZ DEBUG ---<TPlayer|120>--------< getPlayer has been CAUGHT for: "
                + this.playerName + " and got: " + Bukkit.getPlayerExact(this.playerName));
        return Bukkit.getPlayerExact(this.playerName);
    }

    /**
     * Plays a sound for the player at a volume with no pitch modification.
     *
     * @param sound  The sound.
     * @param volume The volume.
     */
    public void playSound(Sound sound, Integer volume) {
        this.playSound(sound, volume, 0);
    }

    /**
     * Plays a sound at the volume of 10
     *
     * @param sound The sound.
     */
    public void playSound(Sound sound) {
        this.playSound(sound, 10);
    }

    /**
     * Plays a sound at a volume with a specific pitch.
     *
     * @param sound  The sound.
     * @param volume The volume.
     * @param pitch  The pitch.
     */
    public void playSound(Sound sound, Integer volume, Integer pitch) {
        if (!this.isOnline())
            return;
        this.getPlayer().playSound(getPlayer().getLocation(), sound, volume, pitch);
    }

    /**
     * Adds a potion effect to a {@link net.tbnr.util.player.TPlayer} quickly.
     *
     * @param type      The potion effect type
     * @param length    The length of the potion effect.
     * @param intensity The intensity of the potion effect.
     * @param ambient   Is this potion effect ambient? Check Bukkit docs for more info on this one.
     */
    public void addPotionEffect(PotionEffectType type, Integer length, Integer intensity, boolean ambient) {
        PotionEffect toAdd = new PotionEffect(type, (length == Integer.MAX_VALUE ? Integer.MAX_VALUE : length * 20),
                intensity, ambient);
        this.getPlayer().addPotionEffect(toAdd);
    }

    /**
     * Adds a potion effect to a {@link net.tbnr.util.player.TPlayer} quickly. Has a default ambiance of "true".
     *
     * @param type      The potion effect type
     * @param length    The length (I believe in ticks).
     * @param intensity The intensity of the potion effect.
     */
    public void addPotionEffect(PotionEffectType type, Integer length, Integer intensity) {
        this.addPotionEffect(type, length, intensity, true);
    }

    /**
     * Adds a potion effect to a {@link net.tbnr.util.player.TPlayer} quickly. Has a default ambiance of "true", and a default intensity of 0.
     *
     * @param type   The potion effect type.
     * @param length The length in ticks
     */
    public void addPotionEffect(PotionEffectType type, Integer length) {
        this.addPotionEffect(type, length, 0);
    }

    /**
     * Adds a potion effect to a player quickly. Adds the potion effect forever, with an ambiance of "true", and an intensity of 0.
     *
     * @param type The type of the potion effect.
     */
    public void addPotionEffect(PotionEffectType type) {
        this.addPotionEffect(type, Integer.MAX_VALUE);
    }

    /**
     * Adds a potion effect to a player quickly, and forever. This allows you to specify an intensity.
     *
     * @param type      The type of the potion effect.
     * @param intensity The intensity of the potion effect. (0 = Level 1)
     */
    public void addInfinitePotionEffect(PotionEffectType type, Integer intensity) {
        this.addPotionEffect(type, Integer.MAX_VALUE, intensity);
    }

    /**
     * This will remove ALL active potion effects except those specified.
     *
     * @param exclusions Specify some potion effect types, or none, and they will not be removed.
     */
    public void removeAllPotionEffects(PotionEffectType... exclusions) {
        List<PotionEffectType> doNotRemove = Arrays.asList(exclusions);
        Player player = this.getPlayer();
        for (PotionEffect effect : player.getActivePotionEffects()) {
            if (doNotRemove.contains(effect.getType()))
                continue;
            player.removePotionEffect(effect.getType());
        }
    }

    /**
     * Remove specified potion effects
     *
     * @param potionEffects Specify the potion effect types to remove. This method will not run if none are specified
     */
    public void removePotionEffects(PotionEffectType... potionEffects) {
        if (potionEffects.length < 1) {
            return;
        }
        List<PotionEffectType> potionEffectTypes = Arrays.asList(potionEffects);
        for (PotionEffect effect : this.getPlayer().getActivePotionEffects()) {
            if (potionEffectTypes.contains(effect.getType()))
                this.getPlayer().removePotionEffect(effect.getType());
        }
    }

    /**
     * Gets The Level of a certain type of potion
     * @param effectType ~ The Type of potion
     * @return the potion level OR -1 if potion not active
     */
    public Integer getCurrentPotionLevel(PotionEffectType effectType) {
        Integer level = -1;
        for (PotionEffect effect : this.getPlayer().getActivePotionEffects()) {
            if (!effect.getType().equals(effectType))
                continue;
            level = effect.getAmplifier();
            break;
        }
        return level;
    }

    /**
     * Gets the Duration of a certain type of potion
     * @param type ~ The type of the potion
     * @return the potion duration OR -1 if potion not active
     */
    public Integer getCurrentPotionDuration(PotionEffectType type) {
        Integer level = -1;
        for (PotionEffect effect : this.getPlayer().getActivePotionEffects()) {
            if (!effect.getType().equals(type))
                continue;
            level = effect.getDuration();
            break;
        }
        return level;
    }

    /**
     * Test if a {@link TPlayer} has certain {@link PotionEffectType}
     *
     * @param effect - The {@link PotionEffectType} to test for.
     * @return True if the {@link TPlayer} has the {@link PotionEffectType}
     */
    public boolean hasPotionEffect(PotionEffectType effect) {
        return effect != null && getPlayer().hasPotionEffect(effect);
    }

    /**
     * Give an item to a {@link net.tbnr.util.player.TPlayer}
     *
     * @param type       The {@link Materia}l of the item
     * @param quantity   The quantity of the item
     * @param data_value The data value (used for wool colors, etc) @see {@link DyeColor}
     * @param title      The title of the item.
     * @param lore       The lore of the item
     * @param slot       The slot to put the item in
     * @return the created {@link ItemStack}
     */
    public ItemStack giveItem(Material type, Integer quantity, short data_value, String title, String[] lore,
            Integer slot) {
        Player player = this.getPlayer();
        if (type == null || quantity < 1)
            return null;

        ItemStack itemStack = new ItemStack(type, quantity);
        if (data_value > 1)
            itemStack.setDurability(data_value);

        ItemMeta meta = itemStack.getItemMeta();
        if (title != null)
            meta.setDisplayName(title);
        if (lore != null)
            meta.setLore(Arrays.asList(lore));
        itemStack.setItemMeta(meta);
        //HotBar slots are from 1-9
        if (slot < 1 || slot > 9) {
            Integer toGive = quantity;
            while (toGive > 0) {
                itemStack.setAmount(Math.min(itemStack.getMaxStackSize(), toGive));
                player.getInventory().addItem(itemStack);
                toGive = toGive - itemStack.getAmount();
            }
        } else {
            player.getInventory().setItem(slot - 1, itemStack);
        }
        return itemStack;
    }

    /**
     * Give an item to a {@link net.tbnr.util.player.TPlayer}
     *
     * @param type       The {@link Material} of the item
     * @param quantity   The quantity of the item
     * @param data_value The data value (used for wool colors, etc) @see {@link DyeColor}
     * @param title      The title of the item.
     * @param lore       The lore of the item
     * @return the created {@link ItemStack}
     */
    public ItemStack giveItem(Material type, Integer quantity, short data_value, String title, String[] lore) {
        return giveItem(type, quantity, data_value, title, lore, -1);
    }

    /**
     * Give an item to a {@link net.tbnr.util.player.TPlayer}
     *
     * @param type       The {@link Material} of the item
     * @param quantity   The quantity of the item
     * @param data_value The data value (used for wool colors, etc)
     * @param title      The title of the item.
     * @return the created {@link ItemStack}
     */
    public ItemStack giveItem(Material type, Integer quantity, short data_value, String title) {
        return giveItem(type, quantity, data_value, title, null);
    }

    /**
     * Give an item to a player
     *
     * @param type       The {@link Material} of the item
     * @param quantity   The quantity of the item
     * @param data_value The data value (used for wool colors, etc)
     * @return the created {@link ItemStack}
     */
    public ItemStack giveItem(Material type, Integer quantity, short data_value) {
        return giveItem(type, quantity, data_value, null);
    }

    /**
     * Give an item to a {@link net.tbnr.util.player.TPlayer}
     *
     * @param type     The material of the item
     * @param quantity The quantity of the item
     */
    public ItemStack giveItem(Material type, Integer quantity) {
        return giveItem(type, quantity, (short) 0);
    }

    /**
     * Gives a single item to a {@link net.tbnr.util.player.TPlayer}
     *
     * @param type The material of the item
     */
    public ItemStack giveItem(Material type) {
        return giveItem(type, 1);
    }

    /**
     * @param material The material of the item to search for
     * @param quantity How many of the items to remove
     * @return If the item was removed (if the user had enough).
     */
    public boolean removeItem(Material material, Integer quantity) {
        if (!getPlayer().getInventory().contains(material, quantity)) {
            return false;
        }
        getPlayer().getInventory().removeItem(new ItemStack(material, quantity));
        return true;
    }

    /**
     * Removes a singular item from the {@link net.tbnr.util.player.TPlayer}'s inventory
     *
     * @param material The material of the item to remove.
     * @return If the item was removed (ie; if they had the item in their inventory)
     */
    public boolean removeItem(Material material) {
        return removeItem(material, 1);
    }

    /**
     * Kills the player.
     */
    public void kill() {
        this.getPlayer().damage(this.getPlayer().getHealth());
    }

    /**
     * Sends messages to the {@link net.tbnr.util.player.TPlayer}
     *
     * @param message The message(s) to send to the {@link net.tbnr.util.player.TPlayer}.
     */
    public void sendMessage(String... message) {
        if (!this.isOnline()) {
            return;
        }
        for (String m : message) {
            this.getPlayer().sendMessage(m);
        }
    }

    /**
     * Called by the {@link net.tbnr.util.player.TPlayerManager} when the player disconnects. Do not call otherwise
     */
    void disconnected() {
        this.playerDocument.put("online", false);
        Object o = getPlayerDocument().get("time-online");
        if (o == null)
            o = 0l;
        if (!(o instanceof Long))
            return;
        long timeOnline = (Long) o;
        long now = Calendar.getInstance().getTimeInMillis();
        timeOnline = timeOnline + (now - timeJoined);
        this.playerDocument.put("time-online", timeOnline);
        this.playerDocument.put("last-seen", now);
        this.save();
    }

    /**
     * Saves the {@link net.tbnr.util.player.TPlayer} {@link com.mongodb.DBObject} to the database.
     */
    public void save() {
        TPlayerManager.getInstance().getCollection().save(this.playerDocument);
    }

    /**
     * Use this to store prefixed and managed data about a {@link net.tbnr.util.player.TPlayer} that can be accessed later.
     *
     * @param plugin   The {@link net.tbnr.util.TPlugin} responsible for storing the data.
     * @param storable The {@link net.tbnr.util.player.TPlayerStorable} object.
     */
    public void store(TPlugin plugin, TPlayerStorable storable) {
        this.playerDocument.put(TPlayer.formatStorable(plugin.getStorablePrefix(), storable.getName()),
                storable.getValue());
        this.save();
    }

    public void store(TPlugin plugin, final String key, final Object o) {
        store(plugin, new TPlayerStorable() {
            @Override
            public String getName() {
                return key;
            }

            @Override
            public Object getValue() {
                return o;
            }
        });
    }

    /**
     * Gets the value of a {@link net.tbnr.util.player.TPlayerStorable}
     *
     * @param plugin   The {@link net.tbnr.util.TPlugin} storing this data. Used for keys.
     * @param storable An empty {@link net.tbnr.util.player.TPlayerStorable} object with the proper data name.
     * @return The stored {@link java.lang.Object}.
     */
    public Object getStorable(TPlugin plugin, TPlayerStorable storable) {
        return this.getStorable(plugin, storable.getName());
    }

    /**
     * Gets the value of a {@link net.tbnr.util.player.TPlayerStorable}
     *
     * @param plugin       The {@link net.tbnr.util.TPlugin} storing this data. Used for keys.
     * @param storable_key The {@link net.tbnr.util.player.TPlayerStorable} key.
     * @return The stored {@link java.lang.Object}.
     */
    public Object getStorable(TPlugin plugin, String storable_key) {
        return this.playerDocument.get(TPlayer.formatStorable(plugin.getStorablePrefix(), storable_key));
    }

    public <T> T getStorable(TPlugin plugin, String storable_key, Class<T> clazz) {
        //noinspection unchecked
        return (T) getStorable(plugin, storable_key);
    }

    /**
     * Formats {@link java.lang.String} for a {@link net.tbnr.util.player.TPlayerStorable} key.
     *
     * @param prefix The prefix of the {@link net.tbnr.util.player.TPlayerStorable} (from the plugin)
     * @param name   The name of the {@link net.tbnr.util.player.TPlayerStorable}
     * @return Fully formatted {@link net.tbnr.util.player.TPlayerStorable} key.
     */
    public static String formatStorable(String prefix, String name) {
        return prefix + "_" + name;
    }

    /**
     * Checks if there is another object matching a {@link net.tbnr.util.player.TPlayerStorable} in the database
     *
     * @param storable The {@link net.tbnr.util.player.TPlayerStorable} prefix of the object
     * @param value    The value to match
     * @return If there is a match!
     */
    public static boolean anyMatchesToStorable(TPlugin plugin, String storable, Object value) {
        DBObject object = new BasicDBObject(TPlayer.formatStorable(plugin.getStorablePrefix(), storable), value);
        DBCursor cursor = TPlayerManager.getInstance().getCollection().find(object);
        return cursor.hasNext();
    }

    /**
     * Gets the amount of time spent online by this {@link org.bukkit.entity.Player} (accurate at time being called)
     *
     * @return The time online in milliseconds.
     */
    public long getTimeOnline() {
        return timeOnline + (Calendar.getInstance().getTimeInMillis() - this.timeJoined);
    }

    /**
     * Plays a particle effect for the user
     *
     * @param effect The effect to play
     * @throws Exception
     */
    public void playParticleEffect(TParticleEffect effect) throws Exception {
        for (ParticleEffect type : effect.getParticleEffectType()) {
            WrapperPlayServerWorldParticles packet = new WrapperPlayServerWorldParticles();
            packet.setParticleName(type.getParticleName());
            packet.setX((float) effect.getLocation().getX());
            packet.setY((float) effect.getLocation().getY());
            packet.setZ((float) effect.getLocation().getZ());
            packet.setOffsetX(effect.getOffset());
            packet.setOffsetY(effect.getHeight());
            packet.setOffsetZ(effect.getOffset());
            packet.setParticleSpeed(effect.getSpeed());
            packet.setNumberOfParticles(effect.getCount());

            packet.sendPacket(getPlayer());
        }
    }

    /**
     * sets a value of an {@link Object} via reflection
     *
     * @param instance  instance the class to use
     * @param fieldName the name of the {@link Field} to modify
     * @param value     the value to set
     * @throws Exception
     */
    public static void setValue(Object instance, String fieldName, Object value) throws Exception {
        Field field = instance.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(instance, value);
    }

    /**
     * Teleports the {@link org.bukkit.entity.Player} to a {@link org.bukkit.Location} with a nice {@link Sound#ENDERMAN_TELEPORT} sound.
     *
     * @param location The {@link org.bukkit.Location} to teleport the {@link org.bukkit.entity.Player} to
     */
    public void teleport(Location location) {
        this.playSound(Sound.ENDERMAN_TELEPORT);
        this.getPlayer().teleport(location);
    }

    /**
     * Clears the {@link org.bukkit.inventory.PlayerInventory} of the {@link org.bukkit.entity.Player}.
     */
    public void clearInventory() {
        this.getPlayer().getInventory().clear();
        this.getPlayer().getInventory().setArmorContents(new ItemStack[4]);
    }

    /**
     * Used to reset everything about the {@link org.bukkit.entity.Player}, can be fine tuned the {@link net.tbnr.util.player.PlayerResetParams}.
     */
    public void resetPlayer(PlayerResetParams params) {
        final Player player = getPlayer();
        player.getInventory().setHeldItemSlot(0);
        if (!isOnline())
            return;
        if (params == null)
            params = new PlayerResetParams();

        if (params.isClearXP()) {
            player.setExp(0);
            player.setLevel(0);
            player.setTotalExperience(0);
        }
        if (params.isClearPotions())
            removeAllPotionEffects();
        if (params.isResetInventory())
            clearInventory();
        if (params.isRestoreHealth()) {
            player.setHealth(player.getMaxHealth());
            player.setRemainingAir(20);
        }
        Bukkit.getScheduler().runTaskLater(Gearz.getInstance(), new Runnable() {
            @Override
            public void run() {
                player.setFireTicks(0);
            }
        }, 2L);
        if (params.isRestoreFood()) {
            player.setFoodLevel(20);
            player.setExhaustion(0);
        }
        player.setSneaking(false);
        if (!params.isResetFlight()) {
            return;
        }

        player.setVelocity(new Vector(0, 0, 0));
        player.setFallDistance(0F);
        player.setAllowFlight(false);
        RandomUtils.setPlayerCollision(player, true);
    }

    /**
     * No params reset.
     */
    public void resetPlayer() {
        this.resetPlayer(null);
    }

    /**
     * Resets the {@link org.bukkit.scoreboard.Scoreboard}
     */
    public void resetScoreboard() {
        if (!this.isOnline())
            return;
        this.scoreboard = Bukkit.getScoreboardManager().getNewScoreboard();
        this.sidebar = null;
        this.getPlayer().setScoreboard(this.scoreboard);
    }

    public void setScoreboardSideTitle(String title) {
        if (!this.isOnline())
            return;

        if (this.sidebar == null) {
            String s = new BigInteger(13, Gearz.getRandom()).toString(5);
            this.sidebar = this.scoreboard.registerNewObjective(s.substring(0, Math.min(s.length(), 15)), "dummy");
            this.sidebar.setDisplaySlot(DisplaySlot.SIDEBAR);
        }
        this.sidebar.setDisplayName(title);
    }

    public void setScoreBoardSide(String key, Integer value) {
        if (!this.isOnline())
            return;

        Score score = this.sidebar.getScore(key.substring(0, Math.min(key.length(), 15)));
        score.setScore(value);
        Player player = getPlayer();
        if (player == null)
            return;
        if (!player.isOnline())
            return;
        player.setScoreboard(this.scoreboard);
    }

    public void removeScoreboardSide(String key) {
        if (!this.isOnline()) {
            return;
        }
        this.scoreboard.resetScores(key);
        getPlayer().setScoreboard(this.scoreboard);
    }

    public static final class TParticleEffect {
        @Getter
        private final Location location;
        @Getter
        private final float height;
        @Getter
        private final float offset;
        @Getter
        private final Integer count;
        @Getter
        private final float speed;
        private final List<ParticleEffect> particleEffectTypes;

        public TParticleEffect(Location location, float height, float offset, Integer count, float speed,
                ParticleEffect... particleEffectType) {
            this.location = location;
            this.height = height;
            this.offset = offset;
            this.count = count;
            this.speed = speed;
            this.particleEffectTypes = Arrays.asList(particleEffectType);
        }

        public List<ParticleEffect> getParticleEffectType() {
            return particleEffectTypes;
        }

    }

    public boolean isOnline() {
        return Bukkit.getPlayer(this.playerName) != null;
    }

    /**
     * Returns the ping asynchronously via the {@link net.tbnr.util.IPUtils.PingCallbackEventHandler} you pass in
     * In that event handler you can do {@link net.tbnr.util.IPUtils.PingCallbackEventHandler#getPing(java.net.InetAddress, net.tbnr.util.IPUtils.PingCallbackEventHandler)} to the passed in {@link net.tbnr.util.IPUtils.PingCallbackEvent}.
     *
     * @param eventHandler ~ The PingCallbackEventHandler
     * @see net.tbnr.util.IPUtils.PingCallbackEvent
     * @see net.tbnr.util.IPUtils.PingCallbackEventHandler
     */
    public void getPing(IPUtils.PingCallbackEventHandler eventHandler) {
        IPUtils.getPing(getPlayer().getAddress().getAddress(), eventHandler);
    }

    public void flashRed() {
        RedFactory.addRed(this);
    }

    public void stopFlashRed() {
        RedFactory.removeRed(this);
    }

    public boolean isFlashingRed() {
        return RedFactory.isRed(this);
    }
}