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().func_98234_c("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}