1143 lines
45 KiB
Java
1143 lines
45 KiB
Java
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<CommandSourceStack> 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<CommandSourceStack> dispatcher, CommandBuildContext buildContext) {
|
|
LiteralCommandNode<CommandSourceStack> 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<CommandSourceStack> list = Lists.<CommandSourceStack>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<CommandSourceStack> list = Lists.<CommandSourceStack>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<CommandSourceStack> list = Lists.<CommandSourceStack>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<CommandSourceStack> list = Lists.<CommandSourceStack>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<CommandSourceStack> list = Lists.<CommandSourceStack>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<CommandSourceStack, ?> wrapStores(
|
|
LiteralCommandNode<CommandSourceStack> parent, LiteralArgumentBuilder<CommandSourceStack> 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<ScoreHolder> 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<Tag> 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<CommandSourceStack, ?> addConditionals(
|
|
CommandNode<CommandSourceStack> parent, LiteralArgumentBuilder<CommandSourceStack> 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<? extends Entity> targets, SlotRange slotRange, Predicate<ItemStack> 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<ItemStack> 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<CommandSourceStack> 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<CommandSourceStack> 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<CommandSourceStack> 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<LootItemCondition> 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<CommandSourceStack> expect(CommandContext<CommandSourceStack> context, boolean actual, boolean expected) {
|
|
return (Collection<CommandSourceStack>)(expected == actual ? Collections.singleton(context.getSource()) : Collections.emptyList());
|
|
}
|
|
|
|
private static ArgumentBuilder<CommandSourceStack, ?> addConditional(
|
|
CommandNode<CommandSourceStack> commandNode, ArgumentBuilder<CommandSourceStack, ?> 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<CommandSourceStack, ?> addIfBlocksConditional(
|
|
CommandNode<CommandSourceStack> commandNode, ArgumentBuilder<CommandSourceStack, ?> 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<CommandSourceStack> 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<CommandSourceStack> 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<CommandSourceStack> 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<CommandSourceStack> expandOneToOneEntityRelation(Function<Entity, Optional<Entity>> relation) {
|
|
return commandContext -> {
|
|
CommandSourceStack commandSourceStack = commandContext.getSource();
|
|
Entity entity = commandSourceStack.getEntity();
|
|
return (Collection<CommandSourceStack>)(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<CommandSourceStack> expandOneToManyEntityRelation(Function<Entity, Stream<Entity>> 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<CommandSourceStack> createRelationOperations(
|
|
CommandNode<CommandSourceStack> node, LiteralArgumentBuilder<CommandSourceStack> 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<?>> entityType) throws CommandSyntaxException {
|
|
Entity entity = SummonCommand.createEntity(source, entityType, source.getPosition(), new CompoundTag(), true);
|
|
return source.withEntity(entity);
|
|
}
|
|
|
|
public static <T extends ExecutionCommandSource<T>> void scheduleFunctionConditionsAndTest(
|
|
T originalSource,
|
|
List<T> sources,
|
|
Function<T, T> sourceModifier,
|
|
IntPredicate successCheck,
|
|
ContextChain<T> contextChain,
|
|
@Nullable CompoundTag arguments,
|
|
ExecutionControl<T> executionControl,
|
|
InCommandFunction<CommandContext<T>, Collection<CommandFunction<T>>> functionsGetter,
|
|
ChainModifiers chainModifiers
|
|
) {
|
|
List<T> list = new ArrayList(sources.size());
|
|
|
|
Collection<CommandFunction<T>> 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<InstantiatedFunction<T>> list2 = new ArrayList(i);
|
|
|
|
try {
|
|
for (CommandFunction<T> 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<T> instantiatedFunction : list2) {
|
|
executionControlx.queueNext(
|
|
new CallFunction<>(instantiatedFunction, executionControlx.currentFrame().returnValueConsumer(), true).bind(executionCommandSource2)
|
|
);
|
|
}
|
|
|
|
executionControlx.queueNext(FallthroughTask.instance());
|
|
},
|
|
commandResultCallback
|
|
)
|
|
);
|
|
}
|
|
|
|
ContextChain<T> contextChain2 = contextChain.nextStage();
|
|
String string = contextChain.getTopContext().getInput();
|
|
executionControl.queueNext(new Continuation<>(string, contextChain2, chainModifiers, originalSource, list));
|
|
}
|
|
}
|
|
|
|
@FunctionalInterface
|
|
interface CommandNumericPredicate {
|
|
int test(CommandContext<CommandSourceStack> commandContext) throws CommandSyntaxException;
|
|
}
|
|
|
|
@FunctionalInterface
|
|
interface CommandPredicate {
|
|
boolean test(CommandContext<CommandSourceStack> commandContext) throws CommandSyntaxException;
|
|
}
|
|
|
|
static class ExecuteIfFunctionCustomModifier implements ModifierAdapter<CommandSourceStack> {
|
|
private final IntPredicate check;
|
|
|
|
ExecuteIfFunctionCustomModifier(boolean invert) {
|
|
this.check = invert ? i -> i != 0 : i -> i == 0;
|
|
}
|
|
|
|
public void apply(
|
|
CommandSourceStack commandSourceStack,
|
|
List<CommandSourceStack> list,
|
|
ContextChain<CommandSourceStack> contextChain,
|
|
ChainModifiers chainModifiers,
|
|
ExecutionControl<CommandSourceStack> 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);
|
|
}
|
|
}
|