114 lines
		
	
	
	
		
			4.4 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			114 lines
		
	
	
	
		
			4.4 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| package net.minecraft.server.commands;
 | |
| 
 | |
| import com.mojang.brigadier.CommandDispatcher;
 | |
| import com.mojang.brigadier.exceptions.CommandSyntaxException;
 | |
| import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
 | |
| import com.mojang.logging.LogUtils;
 | |
| import java.io.IOException;
 | |
| import java.nio.file.Path;
 | |
| import java.nio.file.Paths;
 | |
| import java.util.Locale;
 | |
| import java.util.function.Consumer;
 | |
| import net.minecraft.FileUtil;
 | |
| import net.minecraft.SharedConstants;
 | |
| import net.minecraft.SystemReport;
 | |
| import net.minecraft.Util;
 | |
| import net.minecraft.commands.CommandSourceStack;
 | |
| import net.minecraft.commands.Commands;
 | |
| import net.minecraft.network.chat.Component;
 | |
| import net.minecraft.server.MinecraftServer;
 | |
| import net.minecraft.util.FileZipper;
 | |
| import net.minecraft.util.TimeUtil;
 | |
| import net.minecraft.util.profiling.EmptyProfileResults;
 | |
| import net.minecraft.util.profiling.ProfileResults;
 | |
| import net.minecraft.util.profiling.metrics.storage.MetricsPersister;
 | |
| import org.apache.commons.io.FileUtils;
 | |
| import org.slf4j.Logger;
 | |
| 
 | |
| public class PerfCommand {
 | |
| 	private static final Logger LOGGER = LogUtils.getLogger();
 | |
| 	private static final SimpleCommandExceptionType ERROR_NOT_RUNNING = new SimpleCommandExceptionType(Component.translatable("commands.perf.notRunning"));
 | |
| 	private static final SimpleCommandExceptionType ERROR_ALREADY_RUNNING = new SimpleCommandExceptionType(Component.translatable("commands.perf.alreadyRunning"));
 | |
| 
 | |
| 	public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
 | |
| 		dispatcher.register(
 | |
| 			Commands.literal("perf")
 | |
| 				.requires(Commands.hasPermission(4))
 | |
| 				.then(Commands.literal("start").executes(commandContext -> startProfilingDedicatedServer(commandContext.getSource())))
 | |
| 				.then(Commands.literal("stop").executes(commandContext -> stopProfilingDedicatedServer(commandContext.getSource())))
 | |
| 		);
 | |
| 	}
 | |
| 
 | |
| 	private static int startProfilingDedicatedServer(CommandSourceStack source) throws CommandSyntaxException {
 | |
| 		MinecraftServer minecraftServer = source.getServer();
 | |
| 		if (minecraftServer.isRecordingMetrics()) {
 | |
| 			throw ERROR_ALREADY_RUNNING.create();
 | |
| 		} else {
 | |
| 			Consumer<ProfileResults> consumer = profileResults -> whenStopped(source, profileResults);
 | |
| 			Consumer<Path> consumer2 = path -> saveResults(source, path, minecraftServer);
 | |
| 			minecraftServer.startRecordingMetrics(consumer, consumer2);
 | |
| 			source.sendSuccess(() -> Component.translatable("commands.perf.started"), false);
 | |
| 			return 0;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private static int stopProfilingDedicatedServer(CommandSourceStack source) throws CommandSyntaxException {
 | |
| 		MinecraftServer minecraftServer = source.getServer();
 | |
| 		if (!minecraftServer.isRecordingMetrics()) {
 | |
| 			throw ERROR_NOT_RUNNING.create();
 | |
| 		} else {
 | |
| 			minecraftServer.finishRecordingMetrics();
 | |
| 			return 0;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private static void saveResults(CommandSourceStack source, Path path, MinecraftServer server) {
 | |
| 		String string = String.format(
 | |
| 			Locale.ROOT, "%s-%s-%s", Util.getFilenameFormattedDateTime(), server.getWorldData().getLevelName(), SharedConstants.getCurrentVersion().id()
 | |
| 		);
 | |
| 
 | |
| 		String string2;
 | |
| 		try {
 | |
| 			string2 = FileUtil.findAvailableName(MetricsPersister.PROFILING_RESULTS_DIR, string, ".zip");
 | |
| 		} catch (IOException var11) {
 | |
| 			source.sendFailure(Component.translatable("commands.perf.reportFailed"));
 | |
| 			LOGGER.error("Failed to create report name", (Throwable)var11);
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
| 		FileZipper fileZipper = new FileZipper(MetricsPersister.PROFILING_RESULTS_DIR.resolve(string2));
 | |
| 
 | |
| 		try {
 | |
| 			fileZipper.add(Paths.get("system.txt"), server.fillSystemReport(new SystemReport()).toLineSeparatedString());
 | |
| 			fileZipper.add(path);
 | |
| 		} catch (Throwable var10) {
 | |
| 			try {
 | |
| 				fileZipper.close();
 | |
| 			} catch (Throwable var8) {
 | |
| 				var10.addSuppressed(var8);
 | |
| 			}
 | |
| 
 | |
| 			throw var10;
 | |
| 		}
 | |
| 
 | |
| 		fileZipper.close();
 | |
| 
 | |
| 		try {
 | |
| 			FileUtils.forceDelete(path.toFile());
 | |
| 		} catch (IOException var9) {
 | |
| 			LOGGER.warn("Failed to delete temporary profiling file {}", path, var9);
 | |
| 		}
 | |
| 
 | |
| 		source.sendSuccess(() -> Component.translatable("commands.perf.reportSaved", string2), false);
 | |
| 	}
 | |
| 
 | |
| 	private static void whenStopped(CommandSourceStack source, ProfileResults results) {
 | |
| 		if (results != EmptyProfileResults.EMPTY) {
 | |
| 			int i = results.getTickDuration();
 | |
| 			double d = (double)results.getNanoDuration() / TimeUtil.NANOSECONDS_PER_SECOND;
 | |
| 			source.sendSuccess(
 | |
| 				() -> Component.translatable("commands.perf.stopped", String.format(Locale.ROOT, "%.2f", d), i, String.format(Locale.ROOT, "%.2f", i / d)), false
 | |
| 			);
 | |
| 		}
 | |
| 	}
 | |
| }
 |