package net.minecraft.server.commands; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Lists; import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.RedirectModifier; import com.mojang.brigadier.arguments.DoubleArgumentType; import com.mojang.brigadier.builder.ArgumentBuilder; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.context.ContextChain; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.Dynamic2CommandExceptionType; import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; import com.mojang.brigadier.suggestion.SuggestionProvider; import com.mojang.brigadier.tree.CommandNode; import com.mojang.brigadier.tree.LiteralCommandNode; import it.unimi.dsi.fastutil.ints.IntList; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.OptionalInt; import java.util.function.Function; import java.util.function.IntFunction; import java.util.function.IntPredicate; import java.util.function.Predicate; import java.util.stream.Stream; import net.minecraft.advancements.critereon.MinMaxBounds; import net.minecraft.commands.CommandBuildContext; import net.minecraft.commands.CommandResultCallback; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands; import net.minecraft.commands.ExecutionCommandSource; import net.minecraft.commands.FunctionInstantiationException; import net.minecraft.commands.SharedSuggestionProvider; import net.minecraft.commands.arguments.DimensionArgument; import net.minecraft.commands.arguments.EntityAnchorArgument; import net.minecraft.commands.arguments.EntityArgument; import net.minecraft.commands.arguments.HeightmapTypeArgument; import net.minecraft.commands.arguments.NbtPathArgument; import net.minecraft.commands.arguments.ObjectiveArgument; import net.minecraft.commands.arguments.RangeArgument; import net.minecraft.commands.arguments.ResourceArgument; import net.minecraft.commands.arguments.ResourceLocationArgument; import net.minecraft.commands.arguments.ResourceOrIdArgument; import net.minecraft.commands.arguments.ResourceOrTagArgument; import net.minecraft.commands.arguments.ScoreHolderArgument; import net.minecraft.commands.arguments.SlotsArgument; import net.minecraft.commands.arguments.EntityAnchorArgument.Anchor; import net.minecraft.commands.arguments.RangeArgument.Ints; import net.minecraft.commands.arguments.blocks.BlockPredicateArgument; import net.minecraft.commands.arguments.coordinates.BlockPosArgument; import net.minecraft.commands.arguments.coordinates.RotationArgument; import net.minecraft.commands.arguments.coordinates.SwizzleArgument; import net.minecraft.commands.arguments.coordinates.Vec3Argument; import net.minecraft.commands.arguments.item.FunctionArgument; import net.minecraft.commands.arguments.item.ItemPredicateArgument; import net.minecraft.commands.execution.ChainModifiers; import net.minecraft.commands.execution.ExecutionControl; import net.minecraft.commands.execution.CustomModifierExecutor.ModifierAdapter; import net.minecraft.commands.execution.tasks.CallFunction; import net.minecraft.commands.execution.tasks.FallthroughTask; import net.minecraft.commands.execution.tasks.IsolatedCall; import net.minecraft.commands.execution.tasks.BuildContexts.Continuation; import net.minecraft.commands.functions.CommandFunction; import net.minecraft.commands.functions.InstantiatedFunction; import net.minecraft.commands.synchronization.SuggestionProviders; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.RegistryAccess; import net.minecraft.core.SectionPos; import net.minecraft.core.Holder.Reference; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.ByteTag; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.DoubleTag; import net.minecraft.nbt.FloatTag; import net.minecraft.nbt.IntTag; import net.minecraft.nbt.LongTag; import net.minecraft.nbt.ShortTag; import net.minecraft.nbt.Tag; import net.minecraft.network.chat.Component; import net.minecraft.server.bossevents.CustomBossEvent; import net.minecraft.server.commands.data.DataAccessor; import net.minecraft.server.commands.data.DataCommands; import net.minecraft.server.level.FullChunkStatus; import net.minecraft.server.level.ServerLevel; import net.minecraft.util.Mth; import net.minecraft.world.Container; import net.minecraft.world.entity.Attackable; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.Leashable; import net.minecraft.world.entity.OwnableEntity; import net.minecraft.world.entity.SlotAccess; import net.minecraft.world.entity.Targeting; import net.minecraft.world.entity.TraceableEntity; import net.minecraft.world.inventory.SlotRange; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.pattern.BlockInWorld; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.levelgen.structure.BoundingBox; import net.minecraft.world.level.storage.loot.LootContext; import net.minecraft.world.level.storage.loot.LootParams; import net.minecraft.world.level.storage.loot.LootParams.Builder; import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets; import net.minecraft.world.level.storage.loot.parameters.LootContextParams; import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; import net.minecraft.world.phys.Vec3; import net.minecraft.world.scores.Objective; import net.minecraft.world.scores.ReadOnlyScoreInfo; import net.minecraft.world.scores.ScoreAccess; import net.minecraft.world.scores.ScoreHolder; import net.minecraft.world.scores.Scoreboard; import org.jetbrains.annotations.Nullable; public class ExecuteCommand { private static final int MAX_TEST_AREA = 32768; private static final Dynamic2CommandExceptionType ERROR_AREA_TOO_LARGE = new Dynamic2CommandExceptionType( (object, object2) -> Component.translatableEscape("commands.execute.blocks.toobig", object, object2) ); private static final SimpleCommandExceptionType ERROR_CONDITIONAL_FAILED = new SimpleCommandExceptionType( Component.translatable("commands.execute.conditional.fail") ); private static final DynamicCommandExceptionType ERROR_CONDITIONAL_FAILED_COUNT = new DynamicCommandExceptionType( object -> Component.translatableEscape("commands.execute.conditional.fail_count", object) ); @VisibleForTesting public static final Dynamic2CommandExceptionType ERROR_FUNCTION_CONDITION_INSTANTATION_FAILURE = new Dynamic2CommandExceptionType( (object, object2) -> Component.translatableEscape("commands.execute.function.instantiationFailure", object, object2) ); private static final SuggestionProvider SUGGEST_PREDICATE = (commandContext, suggestionsBuilder) -> { net.minecraft.server.ReloadableServerRegistries.Holder holder = commandContext.getSource().getServer().reloadableRegistries(); return SharedSuggestionProvider.suggestResource(holder.getKeys(Registries.PREDICATE), suggestionsBuilder); }; public static void register(CommandDispatcher dispatcher, CommandBuildContext buildContext) { LiteralCommandNode literalCommandNode = dispatcher.register( Commands.literal("execute").requires(commandSourceStack -> commandSourceStack.hasPermission(2)) ); dispatcher.register( Commands.literal("execute") .requires(commandSourceStack -> commandSourceStack.hasPermission(2)) .then(Commands.literal("run").redirect(dispatcher.getRoot())) .then(addConditionals(literalCommandNode, Commands.literal("if"), true, buildContext)) .then(addConditionals(literalCommandNode, Commands.literal("unless"), false, buildContext)) .then(Commands.literal("as").then(Commands.argument("targets", EntityArgument.entities()).fork(literalCommandNode, commandContext -> { List list = Lists.newArrayList(); for (Entity entity : EntityArgument.getOptionalEntities(commandContext, "targets")) { list.add(commandContext.getSource().withEntity(entity)); } return list; }))) .then(Commands.literal("at").then(Commands.argument("targets", EntityArgument.entities()).fork(literalCommandNode, commandContext -> { List list = Lists.newArrayList(); for (Entity entity : EntityArgument.getOptionalEntities(commandContext, "targets")) { list.add(commandContext.getSource().withLevel((ServerLevel)entity.level()).withPosition(entity.position()).withRotation(entity.getRotationVector())); } return list; }))) .then( Commands.literal("store") .then(wrapStores(literalCommandNode, Commands.literal("result"), true)) .then(wrapStores(literalCommandNode, Commands.literal("success"), false)) ) .then( Commands.literal("positioned") .then( Commands.argument("pos", Vec3Argument.vec3()) .redirect( literalCommandNode, commandContext -> commandContext.getSource().withPosition(Vec3Argument.getVec3(commandContext, "pos")).withAnchor(Anchor.FEET) ) ) .then(Commands.literal("as").then(Commands.argument("targets", EntityArgument.entities()).fork(literalCommandNode, commandContext -> { List list = Lists.newArrayList(); for (Entity entity : EntityArgument.getOptionalEntities(commandContext, "targets")) { list.add(commandContext.getSource().withPosition(entity.position())); } return list; }))) .then(Commands.literal("over").then(Commands.argument("heightmap", HeightmapTypeArgument.heightmap()).redirect(literalCommandNode, commandContext -> { Vec3 vec3 = commandContext.getSource().getPosition(); ServerLevel serverLevel = commandContext.getSource().getLevel(); double d = vec3.x(); double e = vec3.z(); if (!serverLevel.hasChunk(SectionPos.blockToSectionCoord(d), SectionPos.blockToSectionCoord(e))) { throw BlockPosArgument.ERROR_NOT_LOADED.create(); } else { int i = serverLevel.getHeight(HeightmapTypeArgument.getHeightmap(commandContext, "heightmap"), Mth.floor(d), Mth.floor(e)); return commandContext.getSource().withPosition(new Vec3(d, i, e)); } }))) ) .then( Commands.literal("rotated") .then( Commands.argument("rot", RotationArgument.rotation()) .redirect( literalCommandNode, commandContext -> commandContext.getSource().withRotation(RotationArgument.getRotation(commandContext, "rot").getRotation(commandContext.getSource())) ) ) .then(Commands.literal("as").then(Commands.argument("targets", EntityArgument.entities()).fork(literalCommandNode, commandContext -> { List list = Lists.newArrayList(); for (Entity entity : EntityArgument.getOptionalEntities(commandContext, "targets")) { list.add(commandContext.getSource().withRotation(entity.getRotationVector())); } return list; }))) ) .then( Commands.literal("facing") .then( Commands.literal("entity") .then( Commands.argument("targets", EntityArgument.entities()) .then(Commands.argument("anchor", EntityAnchorArgument.anchor()).fork(literalCommandNode, commandContext -> { List list = Lists.newArrayList(); Anchor anchor = EntityAnchorArgument.getAnchor(commandContext, "anchor"); for (Entity entity : EntityArgument.getOptionalEntities(commandContext, "targets")) { list.add(commandContext.getSource().facing(entity, anchor)); } return list; })) ) ) .then( Commands.argument("pos", Vec3Argument.vec3()) .redirect(literalCommandNode, commandContext -> commandContext.getSource().facing(Vec3Argument.getVec3(commandContext, "pos"))) ) ) .then( Commands.literal("align") .then( Commands.argument("axes", SwizzleArgument.swizzle()) .redirect( literalCommandNode, commandContext -> commandContext.getSource() .withPosition(commandContext.getSource().getPosition().align(SwizzleArgument.getSwizzle(commandContext, "axes"))) ) ) ) .then( Commands.literal("anchored") .then( Commands.argument("anchor", EntityAnchorArgument.anchor()) .redirect(literalCommandNode, commandContext -> commandContext.getSource().withAnchor(EntityAnchorArgument.getAnchor(commandContext, "anchor"))) ) ) .then( Commands.literal("in") .then( Commands.argument("dimension", DimensionArgument.dimension()) .redirect(literalCommandNode, commandContext -> commandContext.getSource().withLevel(DimensionArgument.getDimension(commandContext, "dimension"))) ) ) .then( Commands.literal("summon") .then( Commands.argument("entity", ResourceArgument.resource(buildContext, Registries.ENTITY_TYPE)) .suggests(SuggestionProviders.SUMMONABLE_ENTITIES) .redirect( literalCommandNode, commandContext -> spawnEntityAndRedirect(commandContext.getSource(), ResourceArgument.getSummonableEntityType(commandContext, "entity")) ) ) ) .then(createRelationOperations(literalCommandNode, Commands.literal("on"))) ); } private static ArgumentBuilder wrapStores( LiteralCommandNode parent, LiteralArgumentBuilder literal, boolean storingResult ) { literal.then( Commands.literal("score") .then( Commands.argument("targets", ScoreHolderArgument.scoreHolders()) .suggests(ScoreHolderArgument.SUGGEST_SCORE_HOLDERS) .then( Commands.argument("objective", ObjectiveArgument.objective()) .redirect( parent, commandContext -> storeValue( commandContext.getSource(), ScoreHolderArgument.getNamesWithDefaultWildcard(commandContext, "targets"), ObjectiveArgument.getObjective(commandContext, "objective"), storingResult ) ) ) ) ); literal.then( Commands.literal("bossbar") .then( Commands.argument("id", ResourceLocationArgument.id()) .suggests(BossBarCommands.SUGGEST_BOSS_BAR) .then( Commands.literal("value") .redirect(parent, commandContext -> storeValue(commandContext.getSource(), BossBarCommands.getBossBar(commandContext), true, storingResult)) ) .then( Commands.literal("max") .redirect(parent, commandContext -> storeValue(commandContext.getSource(), BossBarCommands.getBossBar(commandContext), false, storingResult)) ) ) ); for (DataCommands.DataProvider dataProvider : DataCommands.TARGET_PROVIDERS) { dataProvider.wrap( literal, argumentBuilder -> argumentBuilder.then( Commands.argument("path", NbtPathArgument.nbtPath()) .then( Commands.literal("int") .then( Commands.argument("scale", DoubleArgumentType.doubleArg()) .redirect( parent, commandContext -> storeData( commandContext.getSource(), dataProvider.access(commandContext), NbtPathArgument.getPath(commandContext, "path"), i -> IntTag.valueOf((int)(i * DoubleArgumentType.getDouble(commandContext, "scale"))), storingResult ) ) ) ) .then( Commands.literal("float") .then( Commands.argument("scale", DoubleArgumentType.doubleArg()) .redirect( parent, commandContext -> storeData( commandContext.getSource(), dataProvider.access(commandContext), NbtPathArgument.getPath(commandContext, "path"), i -> FloatTag.valueOf((float)(i * DoubleArgumentType.getDouble(commandContext, "scale"))), storingResult ) ) ) ) .then( Commands.literal("short") .then( Commands.argument("scale", DoubleArgumentType.doubleArg()) .redirect( parent, commandContext -> storeData( commandContext.getSource(), dataProvider.access(commandContext), NbtPathArgument.getPath(commandContext, "path"), i -> ShortTag.valueOf((short)(i * DoubleArgumentType.getDouble(commandContext, "scale"))), storingResult ) ) ) ) .then( Commands.literal("long") .then( Commands.argument("scale", DoubleArgumentType.doubleArg()) .redirect( parent, commandContext -> storeData( commandContext.getSource(), dataProvider.access(commandContext), NbtPathArgument.getPath(commandContext, "path"), i -> LongTag.valueOf((long)(i * DoubleArgumentType.getDouble(commandContext, "scale"))), storingResult ) ) ) ) .then( Commands.literal("double") .then( Commands.argument("scale", DoubleArgumentType.doubleArg()) .redirect( parent, commandContext -> storeData( commandContext.getSource(), dataProvider.access(commandContext), NbtPathArgument.getPath(commandContext, "path"), i -> DoubleTag.valueOf(i * DoubleArgumentType.getDouble(commandContext, "scale")), storingResult ) ) ) ) .then( Commands.literal("byte") .then( Commands.argument("scale", DoubleArgumentType.doubleArg()) .redirect( parent, commandContext -> storeData( commandContext.getSource(), dataProvider.access(commandContext), NbtPathArgument.getPath(commandContext, "path"), i -> ByteTag.valueOf((byte)(i * DoubleArgumentType.getDouble(commandContext, "scale"))), storingResult ) ) ) ) ) ); } return literal; } private static CommandSourceStack storeValue(CommandSourceStack source, Collection targets, Objective objective, boolean storingResult) { Scoreboard scoreboard = source.getServer().getScoreboard(); return source.withCallback((bl2, i) -> { for (ScoreHolder scoreHolder : targets) { ScoreAccess scoreAccess = scoreboard.getOrCreatePlayerScore(scoreHolder, objective); int j = storingResult ? i : (bl2 ? 1 : 0); scoreAccess.set(j); } }, CommandResultCallback::chain); } private static CommandSourceStack storeValue(CommandSourceStack source, CustomBossEvent bar, boolean storingValue, boolean storingResult) { return source.withCallback((bl3, i) -> { int j = storingResult ? i : (bl3 ? 1 : 0); if (storingValue) { bar.setValue(j); } else { bar.setMax(j); } }, CommandResultCallback::chain); } private static CommandSourceStack storeData( CommandSourceStack source, DataAccessor accessor, NbtPathArgument.NbtPath path, IntFunction tagConverter, boolean storingResult ) { return source.withCallback((bl2, i) -> { try { CompoundTag compoundTag = accessor.getData(); int j = storingResult ? i : (bl2 ? 1 : 0); path.set(compoundTag, (Tag)tagConverter.apply(j)); accessor.setData(compoundTag); } catch (CommandSyntaxException var8) { } }, CommandResultCallback::chain); } private static boolean isChunkLoaded(ServerLevel level, BlockPos pos) { ChunkPos chunkPos = new ChunkPos(pos); LevelChunk levelChunk = level.getChunkSource().getChunkNow(chunkPos.x, chunkPos.z); return levelChunk == null ? false : levelChunk.getFullStatus() == FullChunkStatus.ENTITY_TICKING && level.areEntitiesLoaded(chunkPos.toLong()); } private static ArgumentBuilder addConditionals( CommandNode parent, LiteralArgumentBuilder literal, boolean isIf, CommandBuildContext buildContext ) { literal.then( Commands.literal("block") .then( Commands.argument("pos", BlockPosArgument.blockPos()) .then( addConditional( parent, Commands.argument("block", BlockPredicateArgument.blockPredicate(buildContext)), isIf, commandContext -> BlockPredicateArgument.getBlockPredicate(commandContext, "block") .test(new BlockInWorld(commandContext.getSource().getLevel(), BlockPosArgument.getLoadedBlockPos(commandContext, "pos"), true)) ) ) ) ) .then( Commands.literal("biome") .then( Commands.argument("pos", BlockPosArgument.blockPos()) .then( addConditional( parent, Commands.argument("biome", ResourceOrTagArgument.resourceOrTag(buildContext, Registries.BIOME)), isIf, commandContext -> ResourceOrTagArgument.getResourceOrTag(commandContext, "biome", Registries.BIOME) .test(commandContext.getSource().getLevel().getBiome(BlockPosArgument.getLoadedBlockPos(commandContext, "pos"))) ) ) ) ) .then( Commands.literal("loaded") .then( addConditional( parent, Commands.argument("pos", BlockPosArgument.blockPos()), isIf, commandContext -> isChunkLoaded(commandContext.getSource().getLevel(), BlockPosArgument.getBlockPos(commandContext, "pos")) ) ) ) .then( Commands.literal("dimension") .then( addConditional( parent, Commands.argument("dimension", DimensionArgument.dimension()), isIf, commandContext -> DimensionArgument.getDimension(commandContext, "dimension") == commandContext.getSource().getLevel() ) ) ) .then( Commands.literal("score") .then( Commands.argument("target", ScoreHolderArgument.scoreHolder()) .suggests(ScoreHolderArgument.SUGGEST_SCORE_HOLDERS) .then( Commands.argument("targetObjective", ObjectiveArgument.objective()) .then( Commands.literal("=") .then( Commands.argument("source", ScoreHolderArgument.scoreHolder()) .suggests(ScoreHolderArgument.SUGGEST_SCORE_HOLDERS) .then( addConditional( parent, Commands.argument("sourceObjective", ObjectiveArgument.objective()), isIf, commandContext -> checkScore(commandContext, (i, j) -> i == j) ) ) ) ) .then( Commands.literal("<") .then( Commands.argument("source", ScoreHolderArgument.scoreHolder()) .suggests(ScoreHolderArgument.SUGGEST_SCORE_HOLDERS) .then( addConditional( parent, Commands.argument("sourceObjective", ObjectiveArgument.objective()), isIf, commandContext -> checkScore(commandContext, (i, j) -> i < j) ) ) ) ) .then( Commands.literal("<=") .then( Commands.argument("source", ScoreHolderArgument.scoreHolder()) .suggests(ScoreHolderArgument.SUGGEST_SCORE_HOLDERS) .then( addConditional( parent, Commands.argument("sourceObjective", ObjectiveArgument.objective()), isIf, commandContext -> checkScore(commandContext, (i, j) -> i <= j) ) ) ) ) .then( Commands.literal(">") .then( Commands.argument("source", ScoreHolderArgument.scoreHolder()) .suggests(ScoreHolderArgument.SUGGEST_SCORE_HOLDERS) .then( addConditional( parent, Commands.argument("sourceObjective", ObjectiveArgument.objective()), isIf, commandContext -> checkScore(commandContext, (i, j) -> i > j) ) ) ) ) .then( Commands.literal(">=") .then( Commands.argument("source", ScoreHolderArgument.scoreHolder()) .suggests(ScoreHolderArgument.SUGGEST_SCORE_HOLDERS) .then( addConditional( parent, Commands.argument("sourceObjective", ObjectiveArgument.objective()), isIf, commandContext -> checkScore(commandContext, (i, j) -> i >= j) ) ) ) ) .then( Commands.literal("matches") .then( addConditional( parent, Commands.argument("range", RangeArgument.intRange()), isIf, commandContext -> checkScore(commandContext, Ints.getRange(commandContext, "range")) ) ) ) ) ) ) .then( Commands.literal("blocks") .then( Commands.argument("start", BlockPosArgument.blockPos()) .then( Commands.argument("end", BlockPosArgument.blockPos()) .then( Commands.argument("destination", BlockPosArgument.blockPos()) .then(addIfBlocksConditional(parent, Commands.literal("all"), isIf, false)) .then(addIfBlocksConditional(parent, Commands.literal("masked"), isIf, true)) ) ) ) ) .then( Commands.literal("entity") .then( Commands.argument("entities", EntityArgument.entities()) .fork(parent, commandContext -> expect(commandContext, isIf, !EntityArgument.getOptionalEntities(commandContext, "entities").isEmpty())) .executes(createNumericConditionalHandler(isIf, commandContext -> EntityArgument.getOptionalEntities(commandContext, "entities").size())) ) ) .then( Commands.literal("predicate") .then( addConditional( parent, Commands.argument("predicate", ResourceOrIdArgument.lootPredicate(buildContext)).suggests(SUGGEST_PREDICATE), isIf, commandContext -> checkCustomPredicate(commandContext.getSource(), ResourceOrIdArgument.getLootPredicate(commandContext, "predicate")) ) ) ) .then( Commands.literal("function") .then( Commands.argument("name", FunctionArgument.functions()) .suggests(FunctionCommand.SUGGEST_FUNCTION) .fork(parent, new ExecuteCommand.ExecuteIfFunctionCustomModifier(isIf)) ) ) .then( Commands.literal("items") .then( Commands.literal("entity") .then( Commands.argument("entities", EntityArgument.entities()) .then( Commands.argument("slots", SlotsArgument.slots()) .then( Commands.argument("item_predicate", ItemPredicateArgument.itemPredicate(buildContext)) .fork( parent, commandContext -> expect( commandContext, isIf, countItems( EntityArgument.getEntities(commandContext, "entities"), SlotsArgument.getSlots(commandContext, "slots"), ItemPredicateArgument.getItemPredicate(commandContext, "item_predicate") ) > 0 ) ) .executes( createNumericConditionalHandler( isIf, commandContext -> countItems( EntityArgument.getEntities(commandContext, "entities"), SlotsArgument.getSlots(commandContext, "slots"), ItemPredicateArgument.getItemPredicate(commandContext, "item_predicate") ) ) ) ) ) ) ) .then( Commands.literal("block") .then( Commands.argument("pos", BlockPosArgument.blockPos()) .then( Commands.argument("slots", SlotsArgument.slots()) .then( Commands.argument("item_predicate", ItemPredicateArgument.itemPredicate(buildContext)) .fork( parent, commandContext -> expect( commandContext, isIf, countItems( commandContext.getSource(), BlockPosArgument.getLoadedBlockPos(commandContext, "pos"), SlotsArgument.getSlots(commandContext, "slots"), ItemPredicateArgument.getItemPredicate(commandContext, "item_predicate") ) > 0 ) ) .executes( createNumericConditionalHandler( isIf, commandContext -> countItems( commandContext.getSource(), BlockPosArgument.getLoadedBlockPos(commandContext, "pos"), SlotsArgument.getSlots(commandContext, "slots"), ItemPredicateArgument.getItemPredicate(commandContext, "item_predicate") ) ) ) ) ) ) ) ); for (DataCommands.DataProvider dataProvider : DataCommands.SOURCE_PROVIDERS) { literal.then( dataProvider.wrap( Commands.literal("data"), argumentBuilder -> argumentBuilder.then( Commands.argument("path", NbtPathArgument.nbtPath()) .fork( parent, commandContext -> expect( commandContext, isIf, checkMatchingData(dataProvider.access(commandContext), NbtPathArgument.getPath(commandContext, "path")) > 0 ) ) .executes( createNumericConditionalHandler( isIf, commandContext -> checkMatchingData(dataProvider.access(commandContext), NbtPathArgument.getPath(commandContext, "path")) ) ) ) ) ); } return literal; } private static int countItems(Iterable targets, SlotRange slotRange, Predicate filter) { int i = 0; for (Entity entity : targets) { IntList intList = slotRange.slots(); for (int j = 0; j < intList.size(); j++) { int k = intList.getInt(j); SlotAccess slotAccess = entity.getSlot(k); ItemStack itemStack = slotAccess.get(); if (filter.test(itemStack)) { i += itemStack.getCount(); } } } return i; } private static int countItems(CommandSourceStack source, BlockPos pos, SlotRange slotRange, Predicate filter) throws CommandSyntaxException { int i = 0; Container container = ItemCommands.getContainer(source, pos, ItemCommands.ERROR_SOURCE_NOT_A_CONTAINER); int j = container.getContainerSize(); IntList intList = slotRange.slots(); for (int k = 0; k < intList.size(); k++) { int l = intList.getInt(k); if (l >= 0 && l < j) { ItemStack itemStack = container.getItem(l); if (filter.test(itemStack)) { i += itemStack.getCount(); } } } return i; } private static Command createNumericConditionalHandler(boolean isIf, ExecuteCommand.CommandNumericPredicate predicate) { return isIf ? commandContext -> { int i = predicate.test(commandContext); if (i > 0) { commandContext.getSource().sendSuccess(() -> Component.translatable("commands.execute.conditional.pass_count", i), false); return i; } else { throw ERROR_CONDITIONAL_FAILED.create(); } } : commandContext -> { int i = predicate.test(commandContext); if (i == 0) { commandContext.getSource().sendSuccess(() -> Component.translatable("commands.execute.conditional.pass"), false); return 1; } else { throw ERROR_CONDITIONAL_FAILED_COUNT.create(i); } }; } private static int checkMatchingData(DataAccessor accessor, NbtPathArgument.NbtPath path) throws CommandSyntaxException { return path.countMatching(accessor.getData()); } private static boolean checkScore(CommandContext source, ExecuteCommand.IntBiPredicate predicate) throws CommandSyntaxException { ScoreHolder scoreHolder = ScoreHolderArgument.getName(source, "target"); Objective objective = ObjectiveArgument.getObjective(source, "targetObjective"); ScoreHolder scoreHolder2 = ScoreHolderArgument.getName(source, "source"); Objective objective2 = ObjectiveArgument.getObjective(source, "sourceObjective"); Scoreboard scoreboard = source.getSource().getServer().getScoreboard(); ReadOnlyScoreInfo readOnlyScoreInfo = scoreboard.getPlayerScoreInfo(scoreHolder, objective); ReadOnlyScoreInfo readOnlyScoreInfo2 = scoreboard.getPlayerScoreInfo(scoreHolder2, objective2); return readOnlyScoreInfo != null && readOnlyScoreInfo2 != null ? predicate.test(readOnlyScoreInfo.value(), readOnlyScoreInfo2.value()) : false; } private static boolean checkScore(CommandContext context, MinMaxBounds.Ints bounds) throws CommandSyntaxException { ScoreHolder scoreHolder = ScoreHolderArgument.getName(context, "target"); Objective objective = ObjectiveArgument.getObjective(context, "targetObjective"); Scoreboard scoreboard = context.getSource().getServer().getScoreboard(); ReadOnlyScoreInfo readOnlyScoreInfo = scoreboard.getPlayerScoreInfo(scoreHolder, objective); return readOnlyScoreInfo == null ? false : bounds.matches(readOnlyScoreInfo.value()); } private static boolean checkCustomPredicate(CommandSourceStack source, Holder condition) { ServerLevel serverLevel = source.getLevel(); LootParams lootParams = new Builder(serverLevel) .withParameter(LootContextParams.ORIGIN, source.getPosition()) .withOptionalParameter(LootContextParams.THIS_ENTITY, source.getEntity()) .create(LootContextParamSets.COMMAND); LootContext lootContext = new LootContext.Builder(lootParams).create(Optional.empty()); lootContext.pushVisitedElement(LootContext.createVisitedEntry(condition.value())); return condition.value().test(lootContext); } /** * If actual and expected match, returns a collection containing only the source player. */ private static Collection expect(CommandContext context, boolean actual, boolean expected) { return (Collection)(expected == actual ? Collections.singleton(context.getSource()) : Collections.emptyList()); } private static ArgumentBuilder addConditional( CommandNode commandNode, ArgumentBuilder builder, boolean value, ExecuteCommand.CommandPredicate test ) { return builder.fork(commandNode, commandContext -> expect(commandContext, value, test.test(commandContext))).executes(commandContext -> { if (value == test.test(commandContext)) { commandContext.getSource().sendSuccess(() -> Component.translatable("commands.execute.conditional.pass"), false); return 1; } else { throw ERROR_CONDITIONAL_FAILED.create(); } }); } private static ArgumentBuilder addIfBlocksConditional( CommandNode commandNode, ArgumentBuilder literal, boolean isIf, boolean isMasked ) { return literal.fork(commandNode, commandContext -> expect(commandContext, isIf, checkRegions(commandContext, isMasked).isPresent())) .executes(isIf ? commandContext -> checkIfRegions(commandContext, isMasked) : commandContext -> checkUnlessRegions(commandContext, isMasked)); } private static int checkIfRegions(CommandContext context, boolean isMasked) throws CommandSyntaxException { OptionalInt optionalInt = checkRegions(context, isMasked); if (optionalInt.isPresent()) { context.getSource().sendSuccess(() -> Component.translatable("commands.execute.conditional.pass_count", optionalInt.getAsInt()), false); return optionalInt.getAsInt(); } else { throw ERROR_CONDITIONAL_FAILED.create(); } } private static int checkUnlessRegions(CommandContext context, boolean isMasked) throws CommandSyntaxException { OptionalInt optionalInt = checkRegions(context, isMasked); if (optionalInt.isPresent()) { throw ERROR_CONDITIONAL_FAILED_COUNT.create(optionalInt.getAsInt()); } else { context.getSource().sendSuccess(() -> Component.translatable("commands.execute.conditional.pass"), false); return 1; } } private static OptionalInt checkRegions(CommandContext context, boolean isMasked) throws CommandSyntaxException { return checkRegions( context.getSource().getLevel(), BlockPosArgument.getLoadedBlockPos(context, "start"), BlockPosArgument.getLoadedBlockPos(context, "end"), BlockPosArgument.getLoadedBlockPos(context, "destination"), isMasked ); } private static OptionalInt checkRegions(ServerLevel level, BlockPos begin, BlockPos end, BlockPos destination, boolean isMasked) throws CommandSyntaxException { BoundingBox boundingBox = BoundingBox.fromCorners(begin, end); BoundingBox boundingBox2 = BoundingBox.fromCorners(destination, destination.offset(boundingBox.getLength())); BlockPos blockPos = new BlockPos(boundingBox2.minX() - boundingBox.minX(), boundingBox2.minY() - boundingBox.minY(), boundingBox2.minZ() - boundingBox.minZ()); int i = boundingBox.getXSpan() * boundingBox.getYSpan() * boundingBox.getZSpan(); if (i > 32768) { throw ERROR_AREA_TOO_LARGE.create(32768, i); } else { RegistryAccess registryAccess = level.registryAccess(); int j = 0; for (int k = boundingBox.minZ(); k <= boundingBox.maxZ(); k++) { for (int l = boundingBox.minY(); l <= boundingBox.maxY(); l++) { for (int m = boundingBox.minX(); m <= boundingBox.maxX(); m++) { BlockPos blockPos2 = new BlockPos(m, l, k); BlockPos blockPos3 = blockPos2.offset(blockPos); BlockState blockState = level.getBlockState(blockPos2); if (!isMasked || !blockState.is(Blocks.AIR)) { if (blockState != level.getBlockState(blockPos3)) { return OptionalInt.empty(); } BlockEntity blockEntity = level.getBlockEntity(blockPos2); BlockEntity blockEntity2 = level.getBlockEntity(blockPos3); if (blockEntity != null) { if (blockEntity2 == null) { return OptionalInt.empty(); } if (blockEntity2.getType() != blockEntity.getType()) { return OptionalInt.empty(); } if (!blockEntity.components().equals(blockEntity2.components())) { return OptionalInt.empty(); } CompoundTag compoundTag = blockEntity.saveCustomOnly(registryAccess); CompoundTag compoundTag2 = blockEntity2.saveCustomOnly(registryAccess); if (!compoundTag.equals(compoundTag2)) { return OptionalInt.empty(); } } j++; } } } } return OptionalInt.of(j); } } private static RedirectModifier expandOneToOneEntityRelation(Function> relation) { return commandContext -> { CommandSourceStack commandSourceStack = commandContext.getSource(); Entity entity = commandSourceStack.getEntity(); return (Collection)(entity == null ? List.of() : (Collection)((Optional)relation.apply(entity)) .filter(entityx -> !entityx.isRemoved()) .map(entityx -> List.of(commandSourceStack.withEntity(entityx))) .orElse(List.of())); }; } private static RedirectModifier expandOneToManyEntityRelation(Function> relation) { return commandContext -> { CommandSourceStack commandSourceStack = commandContext.getSource(); Entity entity = commandSourceStack.getEntity(); return entity == null ? List.of() : ((Stream)relation.apply(entity)).filter(entityx -> !entityx.isRemoved()).map(commandSourceStack::withEntity).toList(); }; } private static LiteralArgumentBuilder createRelationOperations( CommandNode node, LiteralArgumentBuilder argumentBuilder ) { return argumentBuilder.then( Commands.literal("owner") .fork( node, expandOneToOneEntityRelation(entity -> entity instanceof OwnableEntity ownableEntity ? Optional.ofNullable(ownableEntity.getOwner()) : Optional.empty()) ) ) .then( Commands.literal("leasher") .fork( node, expandOneToOneEntityRelation(entity -> entity instanceof Leashable leashable ? Optional.ofNullable(leashable.getLeashHolder()) : Optional.empty()) ) ) .then( Commands.literal("target") .fork(node, expandOneToOneEntityRelation(entity -> entity instanceof Targeting targeting ? Optional.ofNullable(targeting.getTarget()) : Optional.empty())) ) .then( Commands.literal("attacker") .fork( node, expandOneToOneEntityRelation(entity -> entity instanceof Attackable attackable ? Optional.ofNullable(attackable.getLastAttacker()) : Optional.empty()) ) ) .then(Commands.literal("vehicle").fork(node, expandOneToOneEntityRelation(entity -> Optional.ofNullable(entity.getVehicle())))) .then(Commands.literal("controller").fork(node, expandOneToOneEntityRelation(entity -> Optional.ofNullable(entity.getControllingPassenger())))) .then( Commands.literal("origin") .fork( node, expandOneToOneEntityRelation( entity -> entity instanceof TraceableEntity traceableEntity ? Optional.ofNullable(traceableEntity.getOwner()) : Optional.empty() ) ) ) .then(Commands.literal("passengers").fork(node, expandOneToManyEntityRelation(entity -> entity.getPassengers().stream()))); } private static CommandSourceStack spawnEntityAndRedirect(CommandSourceStack source, Reference> entityType) throws CommandSyntaxException { Entity entity = SummonCommand.createEntity(source, entityType, source.getPosition(), new CompoundTag(), true); return source.withEntity(entity); } public static > void scheduleFunctionConditionsAndTest( T originalSource, List sources, Function sourceModifier, IntPredicate successCheck, ContextChain contextChain, @Nullable CompoundTag arguments, ExecutionControl executionControl, InCommandFunction, Collection>> functionsGetter, ChainModifiers chainModifiers ) { List list = new ArrayList(sources.size()); Collection> collection; try { collection = functionsGetter.apply(contextChain.getTopContext().copyFor(originalSource)); } catch (CommandSyntaxException var18) { originalSource.handleError(var18, chainModifiers.isForked(), executionControl.tracer()); return; } int i = collection.size(); if (i != 0) { List> list2 = new ArrayList(i); try { for (CommandFunction commandFunction : collection) { try { list2.add(commandFunction.instantiate(arguments, originalSource.dispatcher())); } catch (FunctionInstantiationException var17) { throw ERROR_FUNCTION_CONDITION_INSTANTATION_FAILURE.create(commandFunction.id(), var17.messageComponent()); } } } catch (CommandSyntaxException var19) { originalSource.handleError(var19, chainModifiers.isForked(), executionControl.tracer()); } for (T executionCommandSource : sources) { T executionCommandSource2 = (T)sourceModifier.apply(executionCommandSource.clearCallbacks()); CommandResultCallback commandResultCallback = (bl, ix) -> { if (successCheck.test(ix)) { list.add(executionCommandSource); } }; executionControl.queueNext( new IsolatedCall<>( executionControlx -> { for (InstantiatedFunction instantiatedFunction : list2) { executionControlx.queueNext( new CallFunction<>(instantiatedFunction, executionControlx.currentFrame().returnValueConsumer(), true).bind(executionCommandSource2) ); } executionControlx.queueNext(FallthroughTask.instance()); }, commandResultCallback ) ); } ContextChain contextChain2 = contextChain.nextStage(); String string = contextChain.getTopContext().getInput(); executionControl.queueNext(new Continuation<>(string, contextChain2, chainModifiers, originalSource, list)); } } @FunctionalInterface interface CommandNumericPredicate { int test(CommandContext commandContext) throws CommandSyntaxException; } @FunctionalInterface interface CommandPredicate { boolean test(CommandContext commandContext) throws CommandSyntaxException; } static class ExecuteIfFunctionCustomModifier implements ModifierAdapter { private final IntPredicate check; ExecuteIfFunctionCustomModifier(boolean invert) { this.check = invert ? i -> i != 0 : i -> i == 0; } public void apply( CommandSourceStack commandSourceStack, List list, ContextChain contextChain, ChainModifiers chainModifiers, ExecutionControl executionControl ) { ExecuteCommand.scheduleFunctionConditionsAndTest( commandSourceStack, list, FunctionCommand::modifySenderForExecution, this.check, contextChain, null, executionControl, commandContext -> FunctionArgument.getFunctions(commandContext, "name"), chainModifiers ); } } @FunctionalInterface interface IntBiPredicate { boolean test(int i, int j); } }