    001package net.minecraft.command;
    002
    003import java.io.File;
    004import java.io.FileWriter;
    005import java.text.SimpleDateFormat;
    006import java.util.Date;
    007import java.util.List;
    008import net.minecraft.profiler.ProfilerResult;
    009import net.minecraft.server.MinecraftServer;
    010
    011public class CommandDebug extends CommandBase
    012{
    013    /** Time the debugging started in milliseconds. */
    014    private long startTime = 0L;
    015
    016    /** The number of ticks when debugging started. */
    017    private int startTicks = 0;
    018
    019    public String getCommandName()
    020    {
    021        return "debug";
    022    }
    023
    024    /**
    025     * Return the required permission level for this command.
    026     */
    027    public int getRequiredPermissionLevel()
    028    {
    029        return 3;
    030    }
    031
    032    public void processCommand(ICommandSender par1ICommandSender, String[] par2ArrayOfStr)
    033    {
    034        if (par2ArrayOfStr.length == 1)
    035        {
    036            if (par2ArrayOfStr[0].equals("start"))
    037            {
    038                notifyAdmins(par1ICommandSender, "commands.debug.start", new Object[0]);
    039                MinecraftServer.getServer().enableProfiling();
    040                this.startTime = System.currentTimeMillis();
    041                this.startTicks = MinecraftServer.getServer().getTickCounter();
    042                return;
    043            }
    044
    045            if (par2ArrayOfStr[0].equals("stop"))
    046            {
    047                if (!MinecraftServer.getServer().theProfiler.profilingEnabled)
    048                {
    049                    throw new CommandException("commands.debug.notStarted", new Object[0]);
    050                }
    051
    052                long i = System.currentTimeMillis();
    053                int j = MinecraftServer.getServer().getTickCounter();
    054                long k = i - this.startTime;
    055                int l = j - this.startTicks;
    056                this.saveProfilerResults(k, l);
    057                MinecraftServer.getServer().theProfiler.profilingEnabled = false;
    058                notifyAdmins(par1ICommandSender, "commands.debug.stop", new Object[] {Float.valueOf((float)k / 1000.0F), Integer.valueOf(l)});
    059                return;
    060            }
    061        }
    062
    063        throw new WrongUsageException("commands.debug.usage", new Object[0]);
    064    }
    065
    066    private void saveProfilerResults(long par1, int par3)
    067    {
    068        File file1 = new File(MinecraftServer.getServer().getFile("debug"), "profile-results-" + (new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss")).format(new Date()) + ".txt");
    069        file1.getParentFile().mkdirs();
    070
    071        try
    072        {
    073            FileWriter filewriter = new FileWriter(file1);
    074            filewriter.write(this.getProfilerResults(par1, par3));
    075            filewriter.close();
    076        }
    077        catch (Throwable throwable)
    078        {
    079            MinecraftServer.getServer().getLogAgent().logSevereException("Could not save profiler results to " + file1, throwable);
    080        }
    081    }
    082
    083    private String getProfilerResults(long par1, int par3)
    084    {
    085        StringBuilder stringbuilder = new StringBuilder();
    086        stringbuilder.append("---- Minecraft Profiler Results ----\n");
    087        stringbuilder.append("// ");
    088        stringbuilder.append(getWittyComment());
    089        stringbuilder.append("\n\n");
    090        stringbuilder.append("Time span: ").append(par1).append(" ms\n");
    091        stringbuilder.append("Tick span: ").append(par3).append(" ticks\n");
    092        stringbuilder.append("// This is approximately ").append(String.format("%.2f", new Object[] {Float.valueOf((float)par3 / ((float)par1 / 1000.0F))})).append(" ticks per second. It should be ").append(20).append(" ticks per second\n\n");
    093        stringbuilder.append("--- BEGIN PROFILE DUMP ---\n\n");
    094        this.getProfileDump(0, "root", stringbuilder);
    095        stringbuilder.append("--- END PROFILE DUMP ---\n\n");
    096        return stringbuilder.toString();
    097    }
    098
    099    private void getProfileDump(int par1, String par2Str, StringBuilder par3StringBuilder)
    100    {
    101        List list = MinecraftServer.getServer().theProfiler.getProfilingData(par2Str);
    102
    103        if (list != null && list.size() >= 3)
    104        {
    105            for (int j = 1; j < list.size(); ++j)
    106            {
    107                ProfilerResult profilerresult = (ProfilerResult)list.get(j);
    108                par3StringBuilder.append(String.format("[%02d] ", new Object[] {Integer.valueOf(par1)}));
    109
    110                for (int k = 0; k < par1; ++k)
    111                {
    112                    par3StringBuilder.append(" ");
    113                }
    114
    115                par3StringBuilder.append(profilerresult.field_76331_c);
    116                par3StringBuilder.append(" - ");
    117                par3StringBuilder.append(String.format("%.2f", new Object[] {Double.valueOf(profilerresult.field_76332_a)}));
    118                par3StringBuilder.append("%/");
    119                par3StringBuilder.append(String.format("%.2f", new Object[] {Double.valueOf(profilerresult.field_76330_b)}));
    120                par3StringBuilder.append("%\n");
    121
    122                if (!profilerresult.field_76331_c.equals("unspecified"))
    123                {
    124                    try
    125                    {
    126                        this.getProfileDump(par1 + 1, par2Str + "." + profilerresult.field_76331_c, par3StringBuilder);
    127                    }
    128                    catch (Exception exception)
    129                    {
    130                        par3StringBuilder.append("[[ EXCEPTION " + exception + " ]]");
    131                    }
    132                }
    133            }
    134        }
    135    }
    136
    137    /**
    138     * Returns a random "witty" comment.
    139     */
    140    private static String getWittyComment()
    141    {
    142        String[] astring = new String[] {"Shiny numbers!", "Am I not running fast enough? :(", "I\'m working as hard as I can!", "Will I ever be good enough for you? :(", "Speedy. Zoooooom!", "Hello world", "40% better than a crash report.", "Now with extra numbers", "Now with less numbers", "Now with the same numbers", "You should add flames to things, it makes them go faster!", "Do you feel the need for... optimization?", "*cracks redstone whip*", "Maybe if you treated it better then it\'ll have more motivation to work faster! Poor server."};
    143
    144        try
    145        {
    146            return astring[(int)(System.nanoTime() % (long)astring.length)];
    147        }
    148        catch (Throwable throwable)
    149        {
    150            return "Witty comment unavailable :(";
    151        }
    152    }
    153
    154    /**
    155     * Adds the strings available in this command to the given list of tab completion options.
    156     */
    157    public List addTabCompletionOptions(ICommandSender par1ICommandSender, String[] par2ArrayOfStr)
    158    {
    159        return par2ArrayOfStr.length == 1 ? getListOfStringsMatchingLastWord(par2ArrayOfStr, new String[] {"start", "stop"}): null;
    160    }
    161}