package net.minecraft.server.commands; import com.google.common.collect.Lists; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.Dynamic2CommandExceptionType; import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; import com.mojang.brigadier.suggestion.SuggestionProvider; import java.util.Collection; import java.util.List; import java.util.stream.Collectors; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands; import net.minecraft.commands.SharedSuggestionProvider; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.ComponentUtils; import net.minecraft.server.packs.repository.Pack; import net.minecraft.server.packs.repository.PackRepository; import net.minecraft.server.packs.repository.PackSource; import net.minecraft.world.flag.FeatureFlagSet; import net.minecraft.world.flag.FeatureFlags; public class DataPackCommand { private static final DynamicCommandExceptionType ERROR_UNKNOWN_PACK = new DynamicCommandExceptionType( object -> Component.translatableEscape("commands.datapack.unknown", object) ); private static final DynamicCommandExceptionType ERROR_PACK_ALREADY_ENABLED = new DynamicCommandExceptionType( object -> Component.translatableEscape("commands.datapack.enable.failed", object) ); private static final DynamicCommandExceptionType ERROR_PACK_ALREADY_DISABLED = new DynamicCommandExceptionType( object -> Component.translatableEscape("commands.datapack.disable.failed", object) ); private static final DynamicCommandExceptionType ERROR_CANNOT_DISABLE_FEATURE = new DynamicCommandExceptionType( object -> Component.translatableEscape("commands.datapack.disable.failed.feature", object) ); private static final Dynamic2CommandExceptionType ERROR_PACK_FEATURES_NOT_ENABLED = new Dynamic2CommandExceptionType( (object, object2) -> Component.translatableEscape("commands.datapack.enable.failed.no_flags", object, object2) ); private static final SuggestionProvider SELECTED_PACKS = (commandContext, suggestionsBuilder) -> SharedSuggestionProvider.suggest( commandContext.getSource().getServer().getPackRepository().getSelectedIds().stream().map(StringArgumentType::escapeIfRequired), suggestionsBuilder ); private static final SuggestionProvider UNSELECTED_PACKS = (commandContext, suggestionsBuilder) -> { PackRepository packRepository = commandContext.getSource().getServer().getPackRepository(); Collection collection = packRepository.getSelectedIds(); FeatureFlagSet featureFlagSet = commandContext.getSource().enabledFeatures(); return SharedSuggestionProvider.suggest( packRepository.getAvailablePacks() .stream() .filter(pack -> pack.getRequestedFeatures().isSubsetOf(featureFlagSet)) .map(Pack::getId) .filter(string -> !collection.contains(string)) .map(StringArgumentType::escapeIfRequired), suggestionsBuilder ); }; public static void register(CommandDispatcher dispatcher) { dispatcher.register( Commands.literal("datapack") .requires(commandSourceStack -> commandSourceStack.hasPermission(2)) .then( Commands.literal("enable") .then( Commands.argument("name", StringArgumentType.string()) .suggests(UNSELECTED_PACKS) .executes( commandContext -> enablePack( commandContext.getSource(), getPack(commandContext, "name", true), (list, pack) -> pack.getDefaultPosition().insert(list, pack, Pack::selectionConfig, false) ) ) .then( Commands.literal("after") .then( Commands.argument("existing", StringArgumentType.string()) .suggests(SELECTED_PACKS) .executes( commandContext -> enablePack( commandContext.getSource(), getPack(commandContext, "name", true), (list, pack) -> list.add(list.indexOf(getPack(commandContext, "existing", false)) + 1, pack) ) ) ) ) .then( Commands.literal("before") .then( Commands.argument("existing", StringArgumentType.string()) .suggests(SELECTED_PACKS) .executes( commandContext -> enablePack( commandContext.getSource(), getPack(commandContext, "name", true), (list, pack) -> list.add(list.indexOf(getPack(commandContext, "existing", false)), pack) ) ) ) ) .then(Commands.literal("last").executes(commandContext -> enablePack(commandContext.getSource(), getPack(commandContext, "name", true), List::add))) .then( Commands.literal("first") .executes(commandContext -> enablePack(commandContext.getSource(), getPack(commandContext, "name", true), (list, pack) -> list.add(0, pack))) ) ) ) .then( Commands.literal("disable") .then( Commands.argument("name", StringArgumentType.string()) .suggests(SELECTED_PACKS) .executes(commandContext -> disablePack(commandContext.getSource(), getPack(commandContext, "name", false))) ) ) .then( Commands.literal("list") .executes(commandContext -> listPacks(commandContext.getSource())) .then(Commands.literal("available").executes(commandContext -> listAvailablePacks(commandContext.getSource()))) .then(Commands.literal("enabled").executes(commandContext -> listEnabledPacks(commandContext.getSource()))) ) ); } /** * Enables the given pack. * * @return The number of packs that are loaded after this operation. */ private static int enablePack(CommandSourceStack source, Pack pack, DataPackCommand.Inserter priorityCallback) throws CommandSyntaxException { PackRepository packRepository = source.getServer().getPackRepository(); List list = Lists.newArrayList(packRepository.getSelectedPacks()); priorityCallback.apply(list, pack); source.sendSuccess(() -> Component.translatable("commands.datapack.modify.enable", pack.getChatLink(true)), true); ReloadCommand.reloadPacks((Collection)list.stream().map(Pack::getId).collect(Collectors.toList()), source); return list.size(); } /** * Disables the given pack. * * @return The number of packs that are loaded after this operation. */ private static int disablePack(CommandSourceStack source, Pack pack) { PackRepository packRepository = source.getServer().getPackRepository(); List list = Lists.newArrayList(packRepository.getSelectedPacks()); list.remove(pack); source.sendSuccess(() -> Component.translatable("commands.datapack.modify.disable", pack.getChatLink(true)), true); ReloadCommand.reloadPacks((Collection)list.stream().map(Pack::getId).collect(Collectors.toList()), source); return list.size(); } /** * Sends a list of both enabled and available packs to the user. * * @return The total number of packs. */ private static int listPacks(CommandSourceStack source) { return listEnabledPacks(source) + listAvailablePacks(source); } /** * Sends a list of available packs to the user. * * @return The number of available packs. */ private static int listAvailablePacks(CommandSourceStack source) { PackRepository packRepository = source.getServer().getPackRepository(); packRepository.reload(); Collection collection = packRepository.getSelectedPacks(); Collection collection2 = packRepository.getAvailablePacks(); FeatureFlagSet featureFlagSet = source.enabledFeatures(); List list = collection2.stream().filter(pack -> !collection.contains(pack) && pack.getRequestedFeatures().isSubsetOf(featureFlagSet)).toList(); if (list.isEmpty()) { source.sendSuccess(() -> Component.translatable("commands.datapack.list.available.none"), false); } else { source.sendSuccess( () -> Component.translatable("commands.datapack.list.available.success", list.size(), ComponentUtils.formatList(list, pack -> pack.getChatLink(false))), false ); } return list.size(); } /** * Sends a list of enabled packs to the user. * * @return The number of enabled packs. */ private static int listEnabledPacks(CommandSourceStack source) { PackRepository packRepository = source.getServer().getPackRepository(); packRepository.reload(); Collection collection = packRepository.getSelectedPacks(); if (collection.isEmpty()) { source.sendSuccess(() -> Component.translatable("commands.datapack.list.enabled.none"), false); } else { source.sendSuccess( () -> Component.translatable( "commands.datapack.list.enabled.success", collection.size(), ComponentUtils.formatList(collection, pack -> pack.getChatLink(true)) ), false ); } return collection.size(); } private static Pack getPack(CommandContext context, String name, boolean enabling) throws CommandSyntaxException { String string = StringArgumentType.getString(context, name); PackRepository packRepository = context.getSource().getServer().getPackRepository(); Pack pack = packRepository.getPack(string); if (pack == null) { throw ERROR_UNKNOWN_PACK.create(string); } else { boolean bl = packRepository.getSelectedPacks().contains(pack); if (enabling && bl) { throw ERROR_PACK_ALREADY_ENABLED.create(string); } else if (!enabling && !bl) { throw ERROR_PACK_ALREADY_DISABLED.create(string); } else { FeatureFlagSet featureFlagSet = context.getSource().enabledFeatures(); FeatureFlagSet featureFlagSet2 = pack.getRequestedFeatures(); if (!enabling && !featureFlagSet2.isEmpty() && pack.getPackSource() == PackSource.FEATURE) { throw ERROR_CANNOT_DISABLE_FEATURE.create(string); } else if (!featureFlagSet2.isSubsetOf(featureFlagSet)) { throw ERROR_PACK_FEATURES_NOT_ENABLED.create(string, FeatureFlags.printMissingFlags(featureFlagSet, featureFlagSet2)); } else { return pack; } } } } interface Inserter { void apply(List list, Pack pack) throws CommandSyntaxException; } }