465 lines
		
	
	
	
		
			17 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			465 lines
		
	
	
	
		
			17 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| package net.minecraft.server.commands;
 | |
| 
 | |
| 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 java.util.ArrayList;
 | |
| import java.util.Collection;
 | |
| import java.util.List;
 | |
| import net.minecraft.advancements.Advancement;
 | |
| import net.minecraft.advancements.AdvancementHolder;
 | |
| import net.minecraft.advancements.AdvancementNode;
 | |
| import net.minecraft.advancements.AdvancementProgress;
 | |
| import net.minecraft.advancements.AdvancementTree;
 | |
| import net.minecraft.commands.CommandSourceStack;
 | |
| import net.minecraft.commands.Commands;
 | |
| import net.minecraft.commands.SharedSuggestionProvider;
 | |
| import net.minecraft.commands.arguments.EntityArgument;
 | |
| import net.minecraft.commands.arguments.ResourceKeyArgument;
 | |
| import net.minecraft.core.registries.Registries;
 | |
| import net.minecraft.network.chat.Component;
 | |
| import net.minecraft.server.level.ServerPlayer;
 | |
| 
 | |
| public class AdvancementCommands {
 | |
| 	private static final DynamicCommandExceptionType ERROR_NO_ACTION_PERFORMED = new DynamicCommandExceptionType(object -> (Component)object);
 | |
| 	private static final Dynamic2CommandExceptionType ERROR_CRITERION_NOT_FOUND = new Dynamic2CommandExceptionType(
 | |
| 		(object, object2) -> Component.translatableEscape("commands.advancement.criterionNotFound", object, object2)
 | |
| 	);
 | |
| 
 | |
| 	public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
 | |
| 		dispatcher.register(
 | |
| 			Commands.literal("advancement")
 | |
| 				.requires(Commands.hasPermission(2))
 | |
| 				.then(
 | |
| 					Commands.literal("grant")
 | |
| 						.then(
 | |
| 							Commands.argument("targets", EntityArgument.players())
 | |
| 								.then(
 | |
| 									Commands.literal("only")
 | |
| 										.then(
 | |
| 											Commands.argument("advancement", ResourceKeyArgument.key(Registries.ADVANCEMENT))
 | |
| 												.executes(
 | |
| 													commandContext -> perform(
 | |
| 														commandContext.getSource(),
 | |
| 														EntityArgument.getPlayers(commandContext, "targets"),
 | |
| 														AdvancementCommands.Action.GRANT,
 | |
| 														getAdvancements(commandContext, ResourceKeyArgument.getAdvancement(commandContext, "advancement"), AdvancementCommands.Mode.ONLY)
 | |
| 													)
 | |
| 												)
 | |
| 												.then(
 | |
| 													Commands.argument("criterion", StringArgumentType.greedyString())
 | |
| 														.suggests(
 | |
| 															(commandContext, suggestionsBuilder) -> SharedSuggestionProvider.suggest(
 | |
| 																ResourceKeyArgument.getAdvancement(commandContext, "advancement").value().criteria().keySet(), suggestionsBuilder
 | |
| 															)
 | |
| 														)
 | |
| 														.executes(
 | |
| 															commandContext -> performCriterion(
 | |
| 																commandContext.getSource(),
 | |
| 																EntityArgument.getPlayers(commandContext, "targets"),
 | |
| 																AdvancementCommands.Action.GRANT,
 | |
| 																ResourceKeyArgument.getAdvancement(commandContext, "advancement"),
 | |
| 																StringArgumentType.getString(commandContext, "criterion")
 | |
| 															)
 | |
| 														)
 | |
| 												)
 | |
| 										)
 | |
| 								)
 | |
| 								.then(
 | |
| 									Commands.literal("from")
 | |
| 										.then(
 | |
| 											Commands.argument("advancement", ResourceKeyArgument.key(Registries.ADVANCEMENT))
 | |
| 												.executes(
 | |
| 													commandContext -> perform(
 | |
| 														commandContext.getSource(),
 | |
| 														EntityArgument.getPlayers(commandContext, "targets"),
 | |
| 														AdvancementCommands.Action.GRANT,
 | |
| 														getAdvancements(commandContext, ResourceKeyArgument.getAdvancement(commandContext, "advancement"), AdvancementCommands.Mode.FROM)
 | |
| 													)
 | |
| 												)
 | |
| 										)
 | |
| 								)
 | |
| 								.then(
 | |
| 									Commands.literal("until")
 | |
| 										.then(
 | |
| 											Commands.argument("advancement", ResourceKeyArgument.key(Registries.ADVANCEMENT))
 | |
| 												.executes(
 | |
| 													commandContext -> perform(
 | |
| 														commandContext.getSource(),
 | |
| 														EntityArgument.getPlayers(commandContext, "targets"),
 | |
| 														AdvancementCommands.Action.GRANT,
 | |
| 														getAdvancements(commandContext, ResourceKeyArgument.getAdvancement(commandContext, "advancement"), AdvancementCommands.Mode.UNTIL)
 | |
| 													)
 | |
| 												)
 | |
| 										)
 | |
| 								)
 | |
| 								.then(
 | |
| 									Commands.literal("through")
 | |
| 										.then(
 | |
| 											Commands.argument("advancement", ResourceKeyArgument.key(Registries.ADVANCEMENT))
 | |
| 												.executes(
 | |
| 													commandContext -> perform(
 | |
| 														commandContext.getSource(),
 | |
| 														EntityArgument.getPlayers(commandContext, "targets"),
 | |
| 														AdvancementCommands.Action.GRANT,
 | |
| 														getAdvancements(commandContext, ResourceKeyArgument.getAdvancement(commandContext, "advancement"), AdvancementCommands.Mode.THROUGH)
 | |
| 													)
 | |
| 												)
 | |
| 										)
 | |
| 								)
 | |
| 								.then(
 | |
| 									Commands.literal("everything")
 | |
| 										.executes(
 | |
| 											commandContext -> perform(
 | |
| 												commandContext.getSource(),
 | |
| 												EntityArgument.getPlayers(commandContext, "targets"),
 | |
| 												AdvancementCommands.Action.GRANT,
 | |
| 												commandContext.getSource().getServer().getAdvancements().getAllAdvancements(),
 | |
| 												false
 | |
| 											)
 | |
| 										)
 | |
| 								)
 | |
| 						)
 | |
| 				)
 | |
| 				.then(
 | |
| 					Commands.literal("revoke")
 | |
| 						.then(
 | |
| 							Commands.argument("targets", EntityArgument.players())
 | |
| 								.then(
 | |
| 									Commands.literal("only")
 | |
| 										.then(
 | |
| 											Commands.argument("advancement", ResourceKeyArgument.key(Registries.ADVANCEMENT))
 | |
| 												.executes(
 | |
| 													commandContext -> perform(
 | |
| 														commandContext.getSource(),
 | |
| 														EntityArgument.getPlayers(commandContext, "targets"),
 | |
| 														AdvancementCommands.Action.REVOKE,
 | |
| 														getAdvancements(commandContext, ResourceKeyArgument.getAdvancement(commandContext, "advancement"), AdvancementCommands.Mode.ONLY)
 | |
| 													)
 | |
| 												)
 | |
| 												.then(
 | |
| 													Commands.argument("criterion", StringArgumentType.greedyString())
 | |
| 														.suggests(
 | |
| 															(commandContext, suggestionsBuilder) -> SharedSuggestionProvider.suggest(
 | |
| 																ResourceKeyArgument.getAdvancement(commandContext, "advancement").value().criteria().keySet(), suggestionsBuilder
 | |
| 															)
 | |
| 														)
 | |
| 														.executes(
 | |
| 															commandContext -> performCriterion(
 | |
| 																commandContext.getSource(),
 | |
| 																EntityArgument.getPlayers(commandContext, "targets"),
 | |
| 																AdvancementCommands.Action.REVOKE,
 | |
| 																ResourceKeyArgument.getAdvancement(commandContext, "advancement"),
 | |
| 																StringArgumentType.getString(commandContext, "criterion")
 | |
| 															)
 | |
| 														)
 | |
| 												)
 | |
| 										)
 | |
| 								)
 | |
| 								.then(
 | |
| 									Commands.literal("from")
 | |
| 										.then(
 | |
| 											Commands.argument("advancement", ResourceKeyArgument.key(Registries.ADVANCEMENT))
 | |
| 												.executes(
 | |
| 													commandContext -> perform(
 | |
| 														commandContext.getSource(),
 | |
| 														EntityArgument.getPlayers(commandContext, "targets"),
 | |
| 														AdvancementCommands.Action.REVOKE,
 | |
| 														getAdvancements(commandContext, ResourceKeyArgument.getAdvancement(commandContext, "advancement"), AdvancementCommands.Mode.FROM)
 | |
| 													)
 | |
| 												)
 | |
| 										)
 | |
| 								)
 | |
| 								.then(
 | |
| 									Commands.literal("until")
 | |
| 										.then(
 | |
| 											Commands.argument("advancement", ResourceKeyArgument.key(Registries.ADVANCEMENT))
 | |
| 												.executes(
 | |
| 													commandContext -> perform(
 | |
| 														commandContext.getSource(),
 | |
| 														EntityArgument.getPlayers(commandContext, "targets"),
 | |
| 														AdvancementCommands.Action.REVOKE,
 | |
| 														getAdvancements(commandContext, ResourceKeyArgument.getAdvancement(commandContext, "advancement"), AdvancementCommands.Mode.UNTIL)
 | |
| 													)
 | |
| 												)
 | |
| 										)
 | |
| 								)
 | |
| 								.then(
 | |
| 									Commands.literal("through")
 | |
| 										.then(
 | |
| 											Commands.argument("advancement", ResourceKeyArgument.key(Registries.ADVANCEMENT))
 | |
| 												.executes(
 | |
| 													commandContext -> perform(
 | |
| 														commandContext.getSource(),
 | |
| 														EntityArgument.getPlayers(commandContext, "targets"),
 | |
| 														AdvancementCommands.Action.REVOKE,
 | |
| 														getAdvancements(commandContext, ResourceKeyArgument.getAdvancement(commandContext, "advancement"), AdvancementCommands.Mode.THROUGH)
 | |
| 													)
 | |
| 												)
 | |
| 										)
 | |
| 								)
 | |
| 								.then(
 | |
| 									Commands.literal("everything")
 | |
| 										.executes(
 | |
| 											commandContext -> perform(
 | |
| 												commandContext.getSource(),
 | |
| 												EntityArgument.getPlayers(commandContext, "targets"),
 | |
| 												AdvancementCommands.Action.REVOKE,
 | |
| 												commandContext.getSource().getServer().getAdvancements().getAllAdvancements()
 | |
| 											)
 | |
| 										)
 | |
| 								)
 | |
| 						)
 | |
| 				)
 | |
| 		);
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Performs the given action on each advancement in the list, for each player.
 | |
| 	 * 
 | |
| 	 * @return The number of affected advancements across all players.
 | |
| 	 */
 | |
| 	private static int perform(
 | |
| 		CommandSourceStack source, Collection<ServerPlayer> targets, AdvancementCommands.Action action, Collection<AdvancementHolder> advancements
 | |
| 	) throws CommandSyntaxException {
 | |
| 		return perform(source, targets, action, advancements, true);
 | |
| 	}
 | |
| 
 | |
| 	private static int perform(
 | |
| 		CommandSourceStack source,
 | |
| 		Collection<ServerPlayer> targets,
 | |
| 		AdvancementCommands.Action action,
 | |
| 		Collection<AdvancementHolder> advancements,
 | |
| 		boolean grantEverything
 | |
| 	) throws CommandSyntaxException {
 | |
| 		int i = 0;
 | |
| 
 | |
| 		for (ServerPlayer serverPlayer : targets) {
 | |
| 			i += action.perform(serverPlayer, advancements, grantEverything);
 | |
| 		}
 | |
| 
 | |
| 		if (i == 0) {
 | |
| 			if (advancements.size() == 1) {
 | |
| 				if (targets.size() == 1) {
 | |
| 					throw ERROR_NO_ACTION_PERFORMED.create(
 | |
| 						Component.translatable(
 | |
| 							action.getKey() + ".one.to.one.failure",
 | |
| 							Advancement.name((AdvancementHolder)advancements.iterator().next()),
 | |
| 							((ServerPlayer)targets.iterator().next()).getDisplayName()
 | |
| 						)
 | |
| 					);
 | |
| 				} else {
 | |
| 					throw ERROR_NO_ACTION_PERFORMED.create(
 | |
| 						Component.translatable(action.getKey() + ".one.to.many.failure", Advancement.name((AdvancementHolder)advancements.iterator().next()), targets.size())
 | |
| 					);
 | |
| 				}
 | |
| 			} else if (targets.size() == 1) {
 | |
| 				throw ERROR_NO_ACTION_PERFORMED.create(
 | |
| 					Component.translatable(action.getKey() + ".many.to.one.failure", advancements.size(), ((ServerPlayer)targets.iterator().next()).getDisplayName())
 | |
| 				);
 | |
| 			} else {
 | |
| 				throw ERROR_NO_ACTION_PERFORMED.create(Component.translatable(action.getKey() + ".many.to.many.failure", advancements.size(), targets.size()));
 | |
| 			}
 | |
| 		} else {
 | |
| 			if (advancements.size() == 1) {
 | |
| 				if (targets.size() == 1) {
 | |
| 					source.sendSuccess(
 | |
| 						() -> Component.translatable(
 | |
| 							action.getKey() + ".one.to.one.success",
 | |
| 							Advancement.name((AdvancementHolder)advancements.iterator().next()),
 | |
| 							((ServerPlayer)targets.iterator().next()).getDisplayName()
 | |
| 						),
 | |
| 						true
 | |
| 					);
 | |
| 				} else {
 | |
| 					source.sendSuccess(
 | |
| 						() -> Component.translatable(
 | |
| 							action.getKey() + ".one.to.many.success", Advancement.name((AdvancementHolder)advancements.iterator().next()), targets.size()
 | |
| 						),
 | |
| 						true
 | |
| 					);
 | |
| 				}
 | |
| 			} else if (targets.size() == 1) {
 | |
| 				source.sendSuccess(
 | |
| 					() -> Component.translatable(action.getKey() + ".many.to.one.success", advancements.size(), ((ServerPlayer)targets.iterator().next()).getDisplayName()),
 | |
| 					true
 | |
| 				);
 | |
| 			} else {
 | |
| 				source.sendSuccess(() -> Component.translatable(action.getKey() + ".many.to.many.success", advancements.size(), targets.size()), true);
 | |
| 			}
 | |
| 
 | |
| 			return i;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private static int performCriterion(
 | |
| 		CommandSourceStack source, Collection<ServerPlayer> targets, AdvancementCommands.Action action, AdvancementHolder advancement, String criterionName
 | |
| 	) throws CommandSyntaxException {
 | |
| 		int i = 0;
 | |
| 		Advancement advancement2 = advancement.value();
 | |
| 		if (!advancement2.criteria().containsKey(criterionName)) {
 | |
| 			throw ERROR_CRITERION_NOT_FOUND.create(Advancement.name(advancement), criterionName);
 | |
| 		} else {
 | |
| 			for (ServerPlayer serverPlayer : targets) {
 | |
| 				if (action.performCriterion(serverPlayer, advancement, criterionName)) {
 | |
| 					i++;
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			if (i == 0) {
 | |
| 				if (targets.size() == 1) {
 | |
| 					throw ERROR_NO_ACTION_PERFORMED.create(
 | |
| 						Component.translatable(
 | |
| 							action.getKey() + ".criterion.to.one.failure", criterionName, Advancement.name(advancement), ((ServerPlayer)targets.iterator().next()).getDisplayName()
 | |
| 						)
 | |
| 					);
 | |
| 				} else {
 | |
| 					throw ERROR_NO_ACTION_PERFORMED.create(
 | |
| 						Component.translatable(action.getKey() + ".criterion.to.many.failure", criterionName, Advancement.name(advancement), targets.size())
 | |
| 					);
 | |
| 				}
 | |
| 			} else {
 | |
| 				if (targets.size() == 1) {
 | |
| 					source.sendSuccess(
 | |
| 						() -> Component.translatable(
 | |
| 							action.getKey() + ".criterion.to.one.success", criterionName, Advancement.name(advancement), ((ServerPlayer)targets.iterator().next()).getDisplayName()
 | |
| 						),
 | |
| 						true
 | |
| 					);
 | |
| 				} else {
 | |
| 					source.sendSuccess(
 | |
| 						() -> Component.translatable(action.getKey() + ".criterion.to.many.success", criterionName, Advancement.name(advancement), targets.size()), true
 | |
| 					);
 | |
| 				}
 | |
| 
 | |
| 				return i;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private static List<AdvancementHolder> getAdvancements(
 | |
| 		CommandContext<CommandSourceStack> context, AdvancementHolder advancement, AdvancementCommands.Mode mode
 | |
| 	) {
 | |
| 		AdvancementTree advancementTree = context.getSource().getServer().getAdvancements().tree();
 | |
| 		AdvancementNode advancementNode = advancementTree.get(advancement);
 | |
| 		if (advancementNode == null) {
 | |
| 			return List.of(advancement);
 | |
| 		} else {
 | |
| 			List<AdvancementHolder> list = new ArrayList();
 | |
| 			if (mode.parents) {
 | |
| 				for (AdvancementNode advancementNode2 = advancementNode.parent(); advancementNode2 != null; advancementNode2 = advancementNode2.parent()) {
 | |
| 					list.add(advancementNode2.holder());
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			list.add(advancement);
 | |
| 			if (mode.children) {
 | |
| 				addChildren(advancementNode, list);
 | |
| 			}
 | |
| 
 | |
| 			return list;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private static void addChildren(AdvancementNode node, List<AdvancementHolder> output) {
 | |
| 		for (AdvancementNode advancementNode : node.children()) {
 | |
| 			output.add(advancementNode.holder());
 | |
| 			addChildren(advancementNode, output);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	static enum Action {
 | |
| 		GRANT("grant") {
 | |
| 			@Override
 | |
| 			protected boolean perform(ServerPlayer player, AdvancementHolder advancement) {
 | |
| 				AdvancementProgress advancementProgress = player.getAdvancements().getOrStartProgress(advancement);
 | |
| 				if (advancementProgress.isDone()) {
 | |
| 					return false;
 | |
| 				} else {
 | |
| 					for (String string : advancementProgress.getRemainingCriteria()) {
 | |
| 						player.getAdvancements().award(advancement, string);
 | |
| 					}
 | |
| 
 | |
| 					return true;
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			@Override
 | |
| 			protected boolean performCriterion(ServerPlayer player, AdvancementHolder advancement, String criterionName) {
 | |
| 				return player.getAdvancements().award(advancement, criterionName);
 | |
| 			}
 | |
| 		},
 | |
| 		REVOKE("revoke") {
 | |
| 			@Override
 | |
| 			protected boolean perform(ServerPlayer player, AdvancementHolder advancement) {
 | |
| 				AdvancementProgress advancementProgress = player.getAdvancements().getOrStartProgress(advancement);
 | |
| 				if (!advancementProgress.hasProgress()) {
 | |
| 					return false;
 | |
| 				} else {
 | |
| 					for (String string : advancementProgress.getCompletedCriteria()) {
 | |
| 						player.getAdvancements().revoke(advancement, string);
 | |
| 					}
 | |
| 
 | |
| 					return true;
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			@Override
 | |
| 			protected boolean performCriterion(ServerPlayer player, AdvancementHolder advancement, String criterionName) {
 | |
| 				return player.getAdvancements().revoke(advancement, criterionName);
 | |
| 			}
 | |
| 		};
 | |
| 
 | |
| 		private final String key;
 | |
| 
 | |
| 		Action(final String key) {
 | |
| 			this.key = "commands.advancement." + key;
 | |
| 		}
 | |
| 
 | |
| 		public int perform(ServerPlayer player, Iterable<AdvancementHolder> advancements, boolean grantEverything) {
 | |
| 			int i = 0;
 | |
| 			if (!grantEverything) {
 | |
| 				player.getAdvancements().flushDirty(player, true);
 | |
| 			}
 | |
| 
 | |
| 			for (AdvancementHolder advancementHolder : advancements) {
 | |
| 				if (this.perform(player, advancementHolder)) {
 | |
| 					i++;
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			if (!grantEverything) {
 | |
| 				player.getAdvancements().flushDirty(player, false);
 | |
| 			}
 | |
| 
 | |
| 			return i;
 | |
| 		}
 | |
| 
 | |
| 		protected abstract boolean perform(ServerPlayer player, AdvancementHolder advancement);
 | |
| 
 | |
| 		protected abstract boolean performCriterion(ServerPlayer player, AdvancementHolder advancement, String criterionName);
 | |
| 
 | |
| 		protected String getKey() {
 | |
| 			return this.key;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	static enum Mode {
 | |
| 		ONLY(false, false),
 | |
| 		THROUGH(true, true),
 | |
| 		FROM(false, true),
 | |
| 		UNTIL(true, false),
 | |
| 		EVERYTHING(true, true);
 | |
| 
 | |
| 		final boolean parents;
 | |
| 		final boolean children;
 | |
| 
 | |
| 		private Mode(final boolean parents, final boolean children) {
 | |
| 			this.parents = parents;
 | |
| 			this.children = children;
 | |
| 		}
 | |
| 	}
 | |
| }
 |