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