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 }