001    package net.minecraft.command;
002    
003    import java.io.File;
004    import java.io.FileWriter;
005    import java.text.SimpleDateFormat;
006    import java.util.Date;
007    import java.util.List;
008    import java.util.logging.Level;
009    import java.util.logging.Logger;
010    import net.minecraft.profiler.ProfilerResult;
011    import net.minecraft.server.MinecraftServer;
012    
013    public class CommandDebug extends CommandBase
014    {
015        /** Time the debugging started in milliseconds. */
016        private long startTime = 0L;
017    
018        /** The number of ticks when debugging started. */
019        private int startTicks = 0;
020    
021        public String getCommandName()
022        {
023            return "debug";
024        }
025    
026        /**
027         * Return the required permission level for this command.
028         */
029        public int getRequiredPermissionLevel()
030        {
031            return 3;
032        }
033    
034        public void processCommand(ICommandSender par1ICommandSender, String[] par2ArrayOfStr)
035        {
036            if (par2ArrayOfStr.length == 1)
037            {
038                if (par2ArrayOfStr[0].equals("start"))
039                {
040                    notifyAdmins(par1ICommandSender, "commands.debug.start", new Object[0]);
041                    MinecraftServer.getServer().enableProfiling();
042                    this.startTime = System.currentTimeMillis();
043                    this.startTicks = MinecraftServer.getServer().getTickCounter();
044                    return;
045                }
046    
047                if (par2ArrayOfStr[0].equals("stop"))
048                {
049                    if (!MinecraftServer.getServer().theProfiler.profilingEnabled)
050                    {
051                        throw new CommandException("commands.debug.notStarted", new Object[0]);
052                    }
053    
054                    long var3 = System.currentTimeMillis();
055                    int var5 = MinecraftServer.getServer().getTickCounter();
056                    long var6 = var3 - this.startTime;
057                    int var8 = var5 - this.startTicks;
058                    this.saveProfilerResults(var6, var8);
059                    MinecraftServer.getServer().theProfiler.profilingEnabled = false;
060                    notifyAdmins(par1ICommandSender, "commands.debug.stop", new Object[] {Float.valueOf((float)var6 / 1000.0F), Integer.valueOf(var8)});
061                    return;
062                }
063            }
064    
065            throw new WrongUsageException("commands.debug.usage", new Object[0]);
066        }
067    
068        private void saveProfilerResults(long par1, int par3)
069        {
070            File var4 = new File(MinecraftServer.getServer().getFile("debug"), "profile-results-" + (new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss")).format(new Date()) + ".txt");
071            var4.getParentFile().mkdirs();
072    
073            try
074            {
075                FileWriter var5 = new FileWriter(var4);
076                var5.write(this.getProfilerResults(par1, par3));
077                var5.close();
078            }
079            catch (Throwable var6)
080            {
081                Logger.getLogger("Minecraft").log(Level.SEVERE, "Could not save profiler results to " + var4, var6);
082            }
083        }
084    
085        private String getProfilerResults(long par1, int par3)
086        {
087            StringBuilder var4 = new StringBuilder();
088            var4.append("---- Minecraft Profiler Results ----\n");
089            var4.append("// ");
090            var4.append(getWittyComment());
091            var4.append("\n\n");
092            var4.append("Time span: ").append(par1).append(" ms\n");
093            var4.append("Tick span: ").append(par3).append(" ticks\n");
094            var4.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");
095            var4.append("--- BEGIN PROFILE DUMP ---\n\n");
096            this.getProfileDump(0, "root", var4);
097            var4.append("--- END PROFILE DUMP ---\n\n");
098            return var4.toString();
099        }
100    
101        private void getProfileDump(int par1, String par2Str, StringBuilder par3StringBuilder)
102        {
103            List var4 = MinecraftServer.getServer().theProfiler.getProfilingData(par2Str);
104    
105            if (var4 != null && var4.size() >= 3)
106            {
107                for (int var5 = 1; var5 < var4.size(); ++var5)
108                {
109                    ProfilerResult var6 = (ProfilerResult)var4.get(var5);
110                    par3StringBuilder.append(String.format("[%02d] ", new Object[] {Integer.valueOf(par1)}));
111    
112                    for (int var7 = 0; var7 < par1; ++var7)
113                    {
114                        par3StringBuilder.append(" ");
115                    }
116    
117                    par3StringBuilder.append(var6.field_76331_c);
118                    par3StringBuilder.append(" - ");
119                    par3StringBuilder.append(String.format("%.2f", new Object[] {Double.valueOf(var6.field_76332_a)}));
120                    par3StringBuilder.append("%/");
121                    par3StringBuilder.append(String.format("%.2f", new Object[] {Double.valueOf(var6.field_76330_b)}));
122                    par3StringBuilder.append("%\n");
123    
124                    if (!var6.field_76331_c.equals("unspecified"))
125                    {
126                        try
127                        {
128                            this.getProfileDump(par1 + 1, par2Str + "." + var6.field_76331_c, par3StringBuilder);
129                        }
130                        catch (Exception var8)
131                        {
132                            par3StringBuilder.append("[[ EXCEPTION " + var8 + " ]]");
133                        }
134                    }
135                }
136            }
137        }
138    
139        /**
140         * Returns a random "witty" comment.
141         */
142        private static String getWittyComment()
143        {
144            String[] var0 = 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."};
145    
146            try
147            {
148                return var0[(int)(System.nanoTime() % (long)var0.length)];
149            }
150            catch (Throwable var2)
151            {
152                return "Witty comment unavailable :(";
153            }
154        }
155    
156        /**
157         * Adds the strings available in this command to the given list of tab completion options.
158         */
159        public List addTabCompletionOptions(ICommandSender par1ICommandSender, String[] par2ArrayOfStr)
160        {
161            return par2ArrayOfStr.length == 1 ? getListOfStringsMatchingLastWord(par2ArrayOfStr, new String[] {"start", "stop"}): null;
162        }
163    }