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