de.cubeisland.engine.module.basics.command.general.InformationCommands.java Source code

Java tutorial

Introduction

Here is the source code for de.cubeisland.engine.module.basics.command.general.InformationCommands.java

Source

/**
 * This file is part of CubeEngine.
 * CubeEngine is licensed under the GNU General Public License Version 3.
 *
 * CubeEngine 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.
 *
 * CubeEngine 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 CubeEngine.  If not, see <http://www.gnu.org/licenses/>.
 */
package de.cubeisland.engine.module.basics.command.general;

import java.lang.management.ManagementFactory;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;
import de.cubeisland.engine.butler.filter.Restricted;
import de.cubeisland.engine.butler.parametric.Command;
import de.cubeisland.engine.butler.parametric.Flag;
import de.cubeisland.engine.butler.parametric.Default;
import de.cubeisland.engine.butler.parametric.Label;
import de.cubeisland.engine.butler.parametric.Optional;
import de.cubeisland.engine.butler.parameter.TooFewArgumentsException;
import de.cubeisland.engine.core.command.CommandContext;
import de.cubeisland.engine.core.command.CommandSender;
import de.cubeisland.engine.core.user.User;
import de.cubeisland.engine.core.util.ChatFormat;
import de.cubeisland.engine.core.util.Pair;
import de.cubeisland.engine.core.util.StringUtils;
import de.cubeisland.engine.core.util.matcher.Match;
import de.cubeisland.engine.core.util.math.BlockVector2;
import de.cubeisland.engine.core.util.math.BlockVector3;
import de.cubeisland.engine.module.basics.Basics;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Item;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.joda.time.Duration;
import org.joda.time.format.PeriodFormatter;
import org.joda.time.format.PeriodFormatterBuilder;

import static de.cubeisland.engine.core.util.ChatFormat.*;
import static de.cubeisland.engine.core.util.Direction.matchDirection;
import static de.cubeisland.engine.core.util.formatter.MessageType.*;
import static java.util.Locale.ENGLISH;

public class InformationCommands {
    private final PeriodFormatter formatter;
    private final Basics module;

    public InformationCommands(Basics module) {
        this.module = module;
        this.formatter = new PeriodFormatterBuilder().appendWeeks().appendSuffix(" week", " weeks")
                .appendSeparator(" ").appendDays().appendSuffix(" day", " days").appendSeparator(" ").appendHours()
                .appendSuffix(" hour", " hours").appendSeparator(" ").appendMinutes()
                .appendSuffix(" minute", " minutes").appendSeparator(" ").appendSeconds()
                .appendSuffix(" second", " seconds").toFormatter();
    }

    @Command(desc = "Displays the biome type you are standing in.")
    public void biome(CommandSender context, @Optional World world, @Label("block-x") @Optional Integer x,
            @Label("block-z") @Optional Integer z) {
        if (!(context instanceof User) && (world == null || z == null)) {
            context.sendTranslated(NEGATIVE, "Please provide a world and x and z coordinates!");
            return;
        }
        if (z == null) {
            Location loc = ((User) context).getLocation();
            world = loc.getWorld();
            x = loc.getBlockX();
            z = loc.getBlockZ();
        }
        Biome biome = world.getBiome(x, z);
        context.sendTranslated(NEUTRAL, "Biome at {vector:x\\=:z\\=}: {biome}", new BlockVector2(x, z), biome);
    }

    @Command(desc = "Displays the seed of a world.")
    public void seed(CommandSender context, @Optional World world) {
        if (world == null) {
            if (!(context instanceof User)) {
                throw new TooFewArgumentsException();
            }
            world = ((User) context).getWorld();
        }
        context.sendTranslated(NEUTRAL, "Seed of {world} is {long#seed}", world, world.getSeed());
    }

    @Command(desc = "Displays the direction in which you are looking.")
    @Restricted(value = User.class, msg = "{text:ProTip}: I assume you are looking right at your screen, right?")
    public void compass(User context) {
        int direction = Math.round(context.getLocation().getYaw() + 180f + 360f) % 360;
        context.sendTranslated(NEUTRAL, "You are looking to {input#direction}!",
                matchDirection(direction).translated(context));
    }

    @Command(desc = "Displays your current depth.")
    @Restricted(value = User.class, msg = "You dug too deep!")
    public void depth(User context) {
        final int height = context.getLocation().getBlockY();
        if (height > 62) {
            context.sendTranslated(POSITIVE,
                    "You are on heightlevel {integer#blocks} ({amount#blocks} above sealevel)", height,
                    height - 62);
            return;
        }
        context.sendTranslated(POSITIVE, "You are on heightlevel {integer#blocks} ({amount#blocks} below sealevel)",
                height, 62 - height);
    }

    @Command(desc = "Displays your current location.")
    @Restricted(value = User.class, msg = "Your position: {text:Right in front of your screen!:color=RED}")
    public void getPos(User context) {
        final Location loc = context.getLocation();
        context.sendTranslated(NEUTRAL, "Your position is {vector:x\\=:y\\=:z\\=}",
                new BlockVector3(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
    }

    @Command(desc = "Displays near players(entities/mobs) to you.")
    public void near(CommandSender context, @Optional Integer radius, @Default User player, @Flag boolean entity,
            @Flag boolean mob) {
        if (radius == null) {
            radius = this.module.getConfiguration().commands.nearDefaultRadius;
        }
        int squareRadius = radius * radius;
        Location userLocation = player.getLocation();
        List<Entity> list = userLocation.getWorld().getEntities();
        LinkedList<String> outputlist = new LinkedList<>();
        TreeMap<Double, List<Entity>> sortedMap = new TreeMap<>();
        final Location entityLocation = new Location(null, 0, 0, 0);
        for (Entity e : list) {
            e.getLocation(entityLocation);
            double distance = entityLocation.distanceSquared(userLocation);
            if (!entityLocation.equals(userLocation) && distance < squareRadius) {
                if (entity || (mob && e instanceof LivingEntity) || e instanceof Player) {
                    List<Entity> sublist = sortedMap.get(distance);
                    if (sublist == null) {
                        sublist = new ArrayList<>();
                    }
                    sublist.add(e);
                    sortedMap.put(distance, sublist);
                }
            }
        }
        int i = 0;
        LinkedHashMap<String, Pair<Double, Integer>> groupedEntities = new LinkedHashMap<>();
        for (double dist : sortedMap.keySet()) {
            i++;
            for (Entity e : sortedMap.get(dist)) {
                if (i <= 10) {
                    this.addNearInformation(outputlist, e, Math.sqrt(dist));
                    continue;
                }
                String key;
                if (e instanceof Player) {
                    key = DARK_GREEN + "player";
                } else if (e instanceof LivingEntity) {
                    key = ChatFormat.DARK_AQUA + Match.entity().getNameFor(e.getType());
                } else if (e instanceof Item) {
                    key = ChatFormat.GREY + Match.material().getNameFor(((Item) e).getItemStack());
                } else {
                    key = ChatFormat.GREY + Match.entity().getNameFor(e.getType());
                }
                Pair<Double, Integer> pair = groupedEntities.get(key);
                if (pair == null) {
                    pair = new Pair<>(Math.sqrt(dist), 1);
                    groupedEntities.put(key, pair);
                } else {
                    pair.setRight(pair.getRight() + 1);
                }
            }
        }
        StringBuilder groupedOutput = new StringBuilder();
        for (String key : groupedEntities.keySet()) {
            groupedOutput.append("\n").append(GOLD).append(groupedEntities.get(key).getRight()).append("x ")
                    .append(key).append(WHITE).append(" (").append(GOLD)
                    .append(Math.round(groupedEntities.get(key).getLeft())).append("m").append(WHITE).append(")");
        }
        if (outputlist.isEmpty()) {
            context.sendTranslated(NEGATIVE, "Nothing detected nearby!");
            return;
        }
        String result;
        result = StringUtils.implode(WHITE + ", ", outputlist);
        result += groupedOutput.toString();
        if (context.equals(player)) {
            context.sendTranslated(NEUTRAL, "Found those nearby you:");
            context.sendMessage(result);
            return;
        }
        context.sendTranslated(NEUTRAL, "Found those nearby {user}:", player);
        context.sendMessage(result);
    }

    private void addNearInformation(List<String> list, Entity entity, double distance) {
        String s;
        if (entity instanceof Player) {
            s = DARK_GREEN + ((Player) entity).getName();
        } else if (entity instanceof LivingEntity) {
            s = ChatFormat.DARK_AQUA + Match.entity().getNameFor(entity.getType());
        } else {
            if (entity instanceof Item) {
                s = ChatFormat.GREY + Match.material().getNameFor(((Item) entity).getItemStack());
            } else {
                s = ChatFormat.GREY + Match.entity().getNameFor(entity.getType());
            }
        }
        s += WHITE + " (" + GOLD + distance + "m" + WHITE + ")";
        list.add(s);
    }

    @Command(alias = "pong", desc = "Pong!")
    public void ping(CommandContext context) {
        final String label = context.getInvocation().getLabels().get(0).toLowerCase(ENGLISH);
        if (context.isSource(User.class)) {
            context.sendTranslated(NONE,
                    ("ping".equals(label) ? "pong" : "ping") + "! Your latency: {integer#ping}",
                    ((User) context.getSource()).getPing());
            return;
        }
        context.sendTranslated(NEUTRAL, label + " in the console?");
    }

    @Command(desc = "Displays chunk, memory and world information.")
    public void lag(CommandSender context, @Flag boolean reset) {
        if (reset) {
            if (module.perms().COMMAND_LAG_RESET.isAuthorized(context)) {
                this.module.getLagTimer().resetLowestTPS();
                context.sendTranslated(POSITIVE, "Reset lowest TPS!");
                return;
            }
            context.sendTranslated(NEGATIVE, "You are not allowed to do this!");
            return;
        }
        //Uptime:
        context.sendTranslated(POSITIVE, "[{text:CubeEngine-Basics:color=RED}]");
        DateFormat df = SimpleDateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT,
                context.getLocale());
        Date start = new Date(ManagementFactory.getRuntimeMXBean().getStartTime());
        Duration dura = new Duration(start.getTime(), System.currentTimeMillis());
        context.sendTranslated(POSITIVE, "Server has been running since {input#uptime}", df.format(start));
        context.sendTranslated(POSITIVE, "Uptime: {input#uptime}", formatter.print(dura.toPeriod()));
        //TPS:
        float tps = this.module.getLagTimer().getAverageTPS();
        String color = tps == 20 ? DARK_GREEN.toString()
                : tps > 17 ? YELLOW.toString()
                        : tps > 10 ? RED.toString() : tps == 0 ? (YELLOW.toString() + "NaN") : DARK_RED.toString();
        context.sendTranslated(POSITIVE, "Current TPS: {input#color}{decimal#tps:1}", color, tps);
        Pair<Long, Float> lowestTPS = this.module.getLagTimer().getLowestTPS();
        if (lowestTPS.getRight() != 20) {
            color = ChatFormat
                    .parseFormats(tps > 17 ? YELLOW.toString() : tps > 10 ? RED.toString() : DARK_RED.toString());
            Date date = new Date(lowestTPS.getLeft());
            context.sendTranslated(POSITIVE, "Lowest TPS was {}{decimal#tps:1} ({input#date})", color,
                    lowestTPS.getRight(), df.format(date));
            long timeSinceLastLowTPS = System.currentTimeMillis() - this.module.getLagTimer().getLastLowTPS();
            if (tps == 20 && TimeUnit.MINUTES.convert(timeSinceLastLowTPS, TimeUnit.MILLISECONDS) < 1) {
                context.sendTranslated(NEGATIVE, "TPS was low in the last minute!");
            }
        }
        //Memory
        long memUse = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed() / 1048576;
        long memCom = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getCommitted() / 1048576;
        long memMax = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getMax() / 1048576;
        String memused;
        long memUsePercent = 100 * memUse / memMax;
        if (memUsePercent > 90) {
            if (memUsePercent > 95) {
                memused = DARK_RED.toString();
            } else {
                memused = RED.toString();
            }
        } else if (memUsePercent > 60) {
            memused = YELLOW.toString();
        } else {
            memused = DARK_GREEN.toString();
        }
        memused += memUse;
        context.sendTranslated(POSITIVE, "Memory Usage: {input#memused}/{integer#memcom}/{integer#memMax} MB",
                memused, memCom, memMax);
        //Worlds with loaded Chunks / Entities
        for (World world : Bukkit.getServer().getWorlds()) {
            String type = world.getEnvironment().name();
            int loadedChunks = world.getLoadedChunks().length;
            int entities = world.getEntities().size();
            context.sendTranslated(POSITIVE, "{world} ({input#environment}): {amount} chunks {amount} entities",
                    world, type, loadedChunks, entities);
        }
    }

    @Command(desc = "Displays all loaded worlds", alias = { "worldlist", "worlds" })
    public void listWorlds(CommandSender context) {
        context.sendTranslated(POSITIVE, "Loaded worlds:");
        String format = " " + WHITE + "- " + GOLD + "%s" + WHITE + ":" + INDIGO + "%s";
        for (World world : Bukkit.getServer().getWorlds()) {
            context.sendMessage(String.format(format, world.getName(), world.getEnvironment().name()));
        }
    }
}