DebugCommand.java

net.minecraft.server.commands.DebugCommand

信息

  • 全限定名:net.minecraft.server.commands.DebugCommand
  • 类型:public class
  • 包:net.minecraft.server.commands
  • 源码路径:src/main/java/net/minecraft/server/commands/DebugCommand.java
  • 起始行号:L44
  • 职责:

    TODO

字段/常量

  • LOGGER

    • 类型: Logger
    • 修饰符: private static final
    • 源码定位: L45
    • 说明:

      TODO

  • ERROR_NOT_RUNNING

    • 类型: SimpleCommandExceptionType
    • 修饰符: private static final
    • 源码定位: L46
    • 说明:

      TODO

  • ERROR_ALREADY_RUNNING

    • 类型: SimpleCommandExceptionType
    • 修饰符: private static final
    • 源码定位: L47
    • 说明:

      TODO

  • NO_RECURSIVE_TRACES

    • 类型: SimpleCommandExceptionType
    • 修饰符: private static final
    • 源码定位: L50
    • 说明:

      TODO

  • NO_RETURN_RUN

    • 类型: SimpleCommandExceptionType
    • 修饰符: private static final
    • 源码定位: L53
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.server.commands.DebugCommand.TraceCustomExecutor

    • 类型: class
    • 修饰符: private static
    • 源码定位: L104
    • 说明:

      TODO

  • net.minecraft.server.commands.DebugCommand.Tracer

    • 类型: class
    • 修饰符: private static
    • 源码定位: L177
    • 说明:

      TODO

构造器

方法

下面的方法块按源码顺序生成。

public static void register(CommandDispatcher<CommandSourceStack> dispatcher) @ L57

  • 方法名:register
  • 源码定位:L57
  • 返回类型:void
  • 修饰符:public static

参数:

  • dispatcher: CommandDispatcher

说明:

TODO

private static int start(CommandSourceStack source) @ L75

  • 方法名:start
  • 源码定位:L75
  • 返回类型:int
  • 修饰符:private static

参数:

  • source: CommandSourceStack

说明:

TODO

private static int stop(CommandSourceStack source) @ L86

  • 方法名:stop
  • 源码定位:L86
  • 返回类型:int
  • 修饰符:private static

参数:

  • source: CommandSourceStack

说明:

TODO

代码

public class DebugCommand {
    private static final Logger LOGGER = LogUtils.getLogger();
    private static final SimpleCommandExceptionType ERROR_NOT_RUNNING = new SimpleCommandExceptionType(Component.translatable("commands.debug.notRunning"));
    private static final SimpleCommandExceptionType ERROR_ALREADY_RUNNING = new SimpleCommandExceptionType(
        Component.translatable("commands.debug.alreadyRunning")
    );
    private static final SimpleCommandExceptionType NO_RECURSIVE_TRACES = new SimpleCommandExceptionType(
        Component.translatable("commands.debug.function.noRecursion")
    );
    private static final SimpleCommandExceptionType NO_RETURN_RUN = new SimpleCommandExceptionType(
        Component.translatable("commands.debug.function.noReturnRun")
    );
 
    public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
        dispatcher.register(
            Commands.literal("debug")
                .requires(Commands.hasPermission(Commands.LEVEL_ADMINS))
                .then(Commands.literal("start").executes(c -> start(c.getSource())))
                .then(Commands.literal("stop").executes(c -> stop(c.getSource())))
                .then(
                    Commands.literal("function")
                        .requires(Commands.hasPermission(Commands.LEVEL_ADMINS))
                        .then(
                            Commands.argument("name", FunctionArgument.functions())
                                .suggests(FunctionCommand.SUGGEST_FUNCTION)
                                .executes(new DebugCommand.TraceCustomExecutor())
                        )
                )
        );
    }
 
    private static int start(CommandSourceStack source) throws CommandSyntaxException {
        MinecraftServer server = source.getServer();
        if (server.isTimeProfilerRunning()) {
            throw ERROR_ALREADY_RUNNING.create();
        } else {
            server.startTimeProfiler();
            source.sendSuccess(() -> Component.translatable("commands.debug.started"), true);
            return 0;
        }
    }
 
    private static int stop(CommandSourceStack source) throws CommandSyntaxException {
        MinecraftServer server = source.getServer();
        if (!server.isTimeProfilerRunning()) {
            throw ERROR_NOT_RUNNING.create();
        } else {
            ProfileResults results = server.stopTimeProfiler();
            double seconds = (double)results.getNanoDuration() / TimeUtil.NANOSECONDS_PER_SECOND;
            double tps = results.getTickDuration() / seconds;
            source.sendSuccess(
                () -> Component.translatable(
                    "commands.debug.stopped", String.format(Locale.ROOT, "%.2f", seconds), results.getTickDuration(), String.format(Locale.ROOT, "%.2f", tps)
                ),
                true
            );
            return (int)tps;
        }
    }
 
    private static class TraceCustomExecutor
        extends CustomCommandExecutor.WithErrorHandling<CommandSourceStack>
        implements CustomCommandExecutor.CommandAdapter<CommandSourceStack> {
        public void runGuarded(
            CommandSourceStack source, ContextChain<CommandSourceStack> currentStep, ChainModifiers modifiers, ExecutionControl<CommandSourceStack> context
        ) throws CommandSyntaxException {
            if (modifiers.isReturn()) {
                throw DebugCommand.NO_RETURN_RUN.create();
            } else if (context.tracer() != null) {
                throw DebugCommand.NO_RECURSIVE_TRACES.create();
            } else {
                CommandContext<CommandSourceStack> currentContext = currentStep.getTopContext();
                Collection<CommandFunction<CommandSourceStack>> functions = FunctionArgument.getFunctions(currentContext, "name");
                MinecraftServer server = source.getServer();
                String outputName = "debug-trace-" + Util.getFilenameFormattedDateTime() + ".txt";
                CommandDispatcher<CommandSourceStack> dispatcher = source.getServer().getFunctions().getDispatcher();
                int commandCount = 0;
 
                try {
                    Path dirPath = server.getFile("debug");
                    Files.createDirectories(dirPath);
                    final PrintWriter output = new PrintWriter(Files.newBufferedWriter(dirPath.resolve(outputName), StandardCharsets.UTF_8));
                    DebugCommand.Tracer tracer = new DebugCommand.Tracer(output);
                    context.tracer(tracer);
 
                    for (final CommandFunction<CommandSourceStack> function : functions) {
                        try {
                            CommandSourceStack functionSource = source.withSource(tracer).withMaximumPermission(LevelBasedPermissionSet.GAMEMASTER);
                            InstantiatedFunction<CommandSourceStack> instantiatedFunction = function.instantiate(null, dispatcher);
                            context.queueNext((new CallFunction<CommandSourceStack>(instantiatedFunction, CommandResultCallback.EMPTY, false) {
                                {
                                    Objects.requireNonNull(TraceCustomExecutor.this);
                                }
 
                                public void execute(CommandSourceStack sender, ExecutionContext<CommandSourceStack> contextx, Frame frame) {
                                    output.println(function.id());
                                    super.execute(sender, contextx, frame);
                                }
                            }).bind(functionSource));
                            commandCount += instantiatedFunction.entries().size();
                        } catch (FunctionInstantiationException var18) {
                            source.sendFailure(var18.messageComponent());
                        }
                    }
                } catch (IOException | UncheckedIOException var19) {
                    DebugCommand.LOGGER.warn("Tracing failed", (Throwable)var19);
                    source.sendFailure(Component.translatable("commands.debug.function.traceFailed"));
                }
 
                int finalCommandCount = commandCount;
                context.queueNext(
                    (c, frame) -> {
                        if (functions.size() == 1) {
                            source.sendSuccess(
                                () -> Component.translatable(
                                    "commands.debug.function.success.single",
                                    finalCommandCount,
                                    Component.translationArg(functions.iterator().next().id()),
                                    outputName
                                ),
                                true
                            );
                        } else {
                            source.sendSuccess(
                                () -> Component.translatable("commands.debug.function.success.multiple", finalCommandCount, functions.size(), outputName), true
                            );
                        }
                    }
                );
            }
        }
    }
 
    private static class Tracer implements CommandSource, TraceCallbacks {
        public static final int INDENT_OFFSET = 1;
        private final PrintWriter output;
        private int lastIndent;
        private boolean waitingForResult;
 
        private Tracer(PrintWriter output) {
            this.output = output;
        }
 
        private void indentAndSave(int value) {
            this.printIndent(value);
            this.lastIndent = value;
        }
 
        private void printIndent(int value) {
            for (int i = 0; i < value + 1; i++) {
                this.output.write("    ");
            }
        }
 
        private void newLine() {
            if (this.waitingForResult) {
                this.output.println();
                this.waitingForResult = false;
            }
        }
 
        @Override
        public void onCommand(int depth, String command) {
            this.newLine();
            this.indentAndSave(depth);
            this.output.print("[C] ");
            this.output.print(command);
            this.waitingForResult = true;
        }
 
        @Override
        public void onReturn(int depth, String command, int result) {
            if (this.waitingForResult) {
                this.output.print(" -> ");
                this.output.println(result);
                this.waitingForResult = false;
            } else {
                this.indentAndSave(depth);
                this.output.print("[R = ");
                this.output.print(result);
                this.output.print("] ");
                this.output.println(command);
            }
        }
 
        @Override
        public void onCall(int depth, Identifier function, int size) {
            this.newLine();
            this.indentAndSave(depth);
            this.output.print("[F] ");
            this.output.print(function);
            this.output.print(" size=");
            this.output.println(size);
        }
 
        @Override
        public void onError(String message) {
            this.newLine();
            this.indentAndSave(this.lastIndent + 1);
            this.output.print("[E] ");
            this.output.print(message);
        }
 
        @Override
        public void sendSystemMessage(Component message) {
            this.newLine();
            this.printIndent(this.lastIndent + 1);
            this.output.print("[M] ");
            this.output.println(message.getString());
        }
 
        @Override
        public boolean acceptsSuccess() {
            return true;
        }
 
        @Override
        public boolean acceptsFailure() {
            return true;
        }
 
        @Override
        public boolean shouldInformAdmins() {
            return false;
        }
 
        @Override
        public boolean alwaysAccepts() {
            return true;
        }
 
        @Override
        public void close() {
            IOUtils.closeQuietly((Writer)this.output);
        }
    }
}

引用的其他类

  • CommandSourceStack

    • 引用位置: 参数
  • Commands

    • 引用位置: 方法调用
    • 关联成员: Commands.argument(), Commands.hasPermission(), Commands.literal()
  • FunctionArgument

    • 引用位置: 方法调用
    • 关联成员: FunctionArgument.functions(), FunctionArgument.getFunctions()
  • Component

    • 引用位置: 方法调用
    • 关联成员: Component.translatable(), Component.translationArg()
  • Util

    • 引用位置: 方法调用
    • 关联成员: Util.getFilenameFormattedDateTime()