package net.minecraft.commands.synchronization; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.arguments.ArgumentType; import com.mojang.brigadier.tree.ArgumentCommandNode; import com.mojang.brigadier.tree.CommandNode; import com.mojang.brigadier.tree.LiteralCommandNode; import com.mojang.brigadier.tree.RootCommandNode; import com.mojang.logging.LogUtils; import com.mojang.serialization.JsonOps; import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; import java.util.Collection; import java.util.HashSet; import java.util.Set; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.server.permissions.PermissionCheck; import net.minecraft.server.permissions.PermissionProviderCheck; import org.slf4j.Logger; public class ArgumentUtils { private static final Logger LOGGER = LogUtils.getLogger(); private static final byte NUMBER_FLAG_MIN = 1; private static final byte NUMBER_FLAG_MAX = 2; public static int createNumberFlags(final boolean hasMin, final boolean hasMax) { int result = 0; if (hasMin) { result |= 1; } if (hasMax) { result |= 2; } return result; } public static boolean numberHasMin(final byte flags) { return (flags & 1) != 0; } public static boolean numberHasMax(final byte flags) { return (flags & 2) != 0; } private static , T extends ArgumentTypeInfo.Template> void serializeArgumentCap( final JsonObject result, final ArgumentTypeInfo info, final ArgumentTypeInfo.Template argumentType ) { info.serializeToJson((T)argumentType, result); } private static > void serializeArgumentToJson(final JsonObject result, final T argument) { ArgumentTypeInfo.Template template = ArgumentTypeInfos.unpack(argument); result.addProperty("type", "argument"); result.addProperty("parser", String.valueOf(BuiltInRegistries.COMMAND_ARGUMENT_TYPE.getKey(template.type()))); JsonObject type = new JsonObject(); serializeArgumentCap(type, template.type(), template); if (!type.isEmpty()) { result.add("properties", type); } } public static JsonObject serializeNodeToJson(final CommandDispatcher dispatcher, final CommandNode node) { JsonObject result = new JsonObject(); switch (node) { case RootCommandNode rootNode: result.addProperty("type", "root"); break; case LiteralCommandNode literalNode: result.addProperty("type", "literal"); break; case ArgumentCommandNode argumentNode: serializeArgumentToJson(result, argumentNode.getType()); break; default: LOGGER.error("Could not serialize node {} ({})!", node, node.getClass()); result.addProperty("type", "unknown"); } Collection> children = node.getChildren(); if (!children.isEmpty()) { JsonObject childrenObject = new JsonObject(); for (CommandNode child : children) { childrenObject.add(child.getName(), serializeNodeToJson(dispatcher, child)); } result.add("children", childrenObject); } if (node.getCommand() != null) { result.addProperty("executable", true); } if (node.getRequirement() instanceof PermissionProviderCheck permissionCheck) { JsonElement permissions = PermissionCheck.CODEC .encodeStart(JsonOps.INSTANCE, permissionCheck.test()) .getOrThrow(error -> new IllegalStateException("Failed to serialize requirement: " + error)); result.add("permissions", permissions); } if (node.getRedirect() != null) { Collection path = dispatcher.getPath(node.getRedirect()); if (!path.isEmpty()) { JsonArray target = new JsonArray(); for (String piece : path) { target.add(piece); } result.add("redirect", target); } } return result; } public static Set> findUsedArgumentTypes(final CommandNode node) { Set> visitedNodes = new ReferenceOpenHashSet<>(); Set> result = new HashSet(); findUsedArgumentTypes(node, result, visitedNodes); return result; } private static void findUsedArgumentTypes(final CommandNode node, final Set> output, final Set> visitedNodes) { if (visitedNodes.add(node)) { if (node instanceof ArgumentCommandNode arg) { output.add(arg.getType()); } node.getChildren().forEach(child -> findUsedArgumentTypes(child, output, visitedNodes)); CommandNode redirect = node.getRedirect(); if (redirect != null) { findUsedArgumentTypes(redirect, output, visitedNodes); } } } }