429 lines
32 KiB
Java
429 lines
32 KiB
Java
/*
|
|
* Decompiled with CFR 0.152.
|
|
*
|
|
* Could not load the following classes:
|
|
* com.mojang.brigadier.CommandDispatcher
|
|
* com.mojang.brigadier.Message
|
|
* com.mojang.brigadier.arguments.BoolArgumentType
|
|
* com.mojang.brigadier.arguments.IntegerArgumentType
|
|
* com.mojang.brigadier.arguments.StringArgumentType
|
|
* com.mojang.brigadier.builder.ArgumentBuilder
|
|
* com.mojang.brigadier.builder.LiteralArgumentBuilder
|
|
* com.mojang.brigadier.builder.RequiredArgumentBuilder
|
|
* com.mojang.brigadier.context.CommandContext
|
|
* com.mojang.brigadier.exceptions.CommandSyntaxException
|
|
* com.mojang.brigadier.exceptions.Dynamic3CommandExceptionType
|
|
* com.mojang.brigadier.exceptions.DynamicCommandExceptionType
|
|
* com.mojang.brigadier.exceptions.SimpleCommandExceptionType
|
|
* com.mojang.brigadier.suggestion.Suggestions
|
|
* com.mojang.brigadier.suggestion.SuggestionsBuilder
|
|
* org.apache.commons.lang3.mutable.MutableInt
|
|
*/
|
|
package net.minecraft.gametest.framework;
|
|
|
|
import com.mojang.brigadier.CommandDispatcher;
|
|
import com.mojang.brigadier.Message;
|
|
import com.mojang.brigadier.arguments.BoolArgumentType;
|
|
import com.mojang.brigadier.arguments.IntegerArgumentType;
|
|
import com.mojang.brigadier.arguments.StringArgumentType;
|
|
import com.mojang.brigadier.builder.ArgumentBuilder;
|
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
|
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
|
import com.mojang.brigadier.context.CommandContext;
|
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
|
import com.mojang.brigadier.exceptions.Dynamic3CommandExceptionType;
|
|
import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
|
|
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
|
|
import com.mojang.brigadier.suggestion.Suggestions;
|
|
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
|
import java.util.ArrayList;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.Locale;
|
|
import java.util.Optional;
|
|
import java.util.concurrent.CompletableFuture;
|
|
import java.util.function.Function;
|
|
import java.util.stream.Stream;
|
|
import net.minecraft.ChatFormatting;
|
|
import net.minecraft.SharedConstants;
|
|
import net.minecraft.commands.CommandBuildContext;
|
|
import net.minecraft.commands.CommandSourceStack;
|
|
import net.minecraft.commands.Commands;
|
|
import net.minecraft.commands.SharedSuggestionProvider;
|
|
import net.minecraft.commands.arguments.IdentifierArgument;
|
|
import net.minecraft.commands.arguments.ResourceArgument;
|
|
import net.minecraft.commands.arguments.ResourceSelectorArgument;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.Direction;
|
|
import net.minecraft.core.Holder;
|
|
import net.minecraft.core.Registry;
|
|
import net.minecraft.core.Vec3i;
|
|
import net.minecraft.core.registries.Registries;
|
|
import net.minecraft.gametest.framework.FailedTestTracker;
|
|
import net.minecraft.gametest.framework.GameTestBatch;
|
|
import net.minecraft.gametest.framework.GameTestBatchFactory;
|
|
import net.minecraft.gametest.framework.GameTestBatchListener;
|
|
import net.minecraft.gametest.framework.GameTestInfo;
|
|
import net.minecraft.gametest.framework.GameTestInstance;
|
|
import net.minecraft.gametest.framework.GameTestListener;
|
|
import net.minecraft.gametest.framework.GameTestRunner;
|
|
import net.minecraft.gametest.framework.GameTestTicker;
|
|
import net.minecraft.gametest.framework.MultipleTestTracker;
|
|
import net.minecraft.gametest.framework.RetryOptions;
|
|
import net.minecraft.gametest.framework.StructureGridSpawner;
|
|
import net.minecraft.gametest.framework.StructureUtils;
|
|
import net.minecraft.gametest.framework.TestFinder;
|
|
import net.minecraft.gametest.framework.TestInstanceFinder;
|
|
import net.minecraft.gametest.framework.TestPosFinder;
|
|
import net.minecraft.network.chat.ClickEvent;
|
|
import net.minecraft.network.chat.Component;
|
|
import net.minecraft.network.chat.ComponentUtils;
|
|
import net.minecraft.network.chat.HoverEvent;
|
|
import net.minecraft.network.chat.MutableComponent;
|
|
import net.minecraft.network.chat.Style;
|
|
import net.minecraft.network.protocol.game.ClientboundGameTestHighlightPosPacket;
|
|
import net.minecraft.resources.Identifier;
|
|
import net.minecraft.server.commands.InCommandFunction;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
import net.minecraft.server.level.ServerPlayer;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.world.level.block.Blocks;
|
|
import net.minecraft.world.level.block.Rotation;
|
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
|
import net.minecraft.world.level.block.entity.BlockEntityType;
|
|
import net.minecraft.world.level.block.entity.TestInstanceBlockEntity;
|
|
import net.minecraft.world.level.levelgen.Heightmap;
|
|
import net.minecraft.world.phys.BlockHitResult;
|
|
import org.apache.commons.lang3.mutable.MutableInt;
|
|
|
|
public class TestCommand {
|
|
public static final int TEST_NEARBY_SEARCH_RADIUS = 15;
|
|
public static final int TEST_FULL_SEARCH_RADIUS = 250;
|
|
public static final int VERIFY_TEST_GRID_AXIS_SIZE = 10;
|
|
public static final int VERIFY_TEST_BATCH_SIZE = 100;
|
|
private static final int DEFAULT_CLEAR_RADIUS = 250;
|
|
private static final int MAX_CLEAR_RADIUS = 1024;
|
|
private static final int TEST_POS_Z_OFFSET_FROM_PLAYER = 3;
|
|
private static final int DEFAULT_X_SIZE = 5;
|
|
private static final int DEFAULT_Y_SIZE = 5;
|
|
private static final int DEFAULT_Z_SIZE = 5;
|
|
private static final SimpleCommandExceptionType CLEAR_NO_TESTS = new SimpleCommandExceptionType((Message)Component.translatable("commands.test.clear.error.no_tests"));
|
|
private static final SimpleCommandExceptionType RESET_NO_TESTS = new SimpleCommandExceptionType((Message)Component.translatable("commands.test.reset.error.no_tests"));
|
|
private static final SimpleCommandExceptionType TEST_INSTANCE_COULD_NOT_BE_FOUND = new SimpleCommandExceptionType((Message)Component.translatable("commands.test.error.test_instance_not_found"));
|
|
private static final SimpleCommandExceptionType NO_STRUCTURES_TO_EXPORT = new SimpleCommandExceptionType((Message)Component.literal("Could not find any structures to export"));
|
|
private static final SimpleCommandExceptionType NO_TEST_INSTANCES = new SimpleCommandExceptionType((Message)Component.translatable("commands.test.error.no_test_instances"));
|
|
private static final Dynamic3CommandExceptionType NO_TEST_CONTAINING = new Dynamic3CommandExceptionType((x, y, z) -> Component.translatableEscape("commands.test.error.no_test_containing_pos", x, y, z));
|
|
private static final DynamicCommandExceptionType TOO_LARGE = new DynamicCommandExceptionType(size -> Component.translatableEscape("commands.test.error.too_large", size));
|
|
|
|
private static int reset(TestFinder finder) throws CommandSyntaxException {
|
|
TestCommand.stopTests();
|
|
int count = TestCommand.toGameTestInfos(finder.source(), RetryOptions.noRetries(), finder).map(info -> TestCommand.resetGameTestInfo(finder.source(), info)).toList().size();
|
|
if (count == 0) {
|
|
throw CLEAR_NO_TESTS.create();
|
|
}
|
|
finder.source().sendSuccess(() -> Component.translatable("commands.test.reset.success", count), true);
|
|
return count;
|
|
}
|
|
|
|
private static int clear(TestFinder finder) throws CommandSyntaxException {
|
|
TestCommand.stopTests();
|
|
CommandSourceStack source = finder.source();
|
|
ServerLevel level = source.getLevel();
|
|
List tests = finder.findTestPos().flatMap(pos -> level.getBlockEntity((BlockPos)pos, BlockEntityType.TEST_INSTANCE_BLOCK).stream()).toList();
|
|
for (TestInstanceBlockEntity testInstanceBlockEntity : tests) {
|
|
StructureUtils.clearSpaceForStructure(testInstanceBlockEntity.getStructureBoundingBox(), level);
|
|
testInstanceBlockEntity.removeBarriers();
|
|
level.destroyBlock(testInstanceBlockEntity.getBlockPos(), false);
|
|
}
|
|
if (tests.isEmpty()) {
|
|
throw CLEAR_NO_TESTS.create();
|
|
}
|
|
source.sendSuccess(() -> Component.translatable("commands.test.clear.success", tests.size()), true);
|
|
return tests.size();
|
|
}
|
|
|
|
private static int export(TestFinder finder) throws CommandSyntaxException {
|
|
CommandSourceStack source = finder.source();
|
|
ServerLevel level = source.getLevel();
|
|
int count = 0;
|
|
boolean allGood = true;
|
|
Iterator iterator = finder.findTestPos().iterator();
|
|
while (iterator.hasNext()) {
|
|
BlockPos pos = (BlockPos)iterator.next();
|
|
BlockEntity blockEntity = level.getBlockEntity(pos);
|
|
if (blockEntity instanceof TestInstanceBlockEntity) {
|
|
TestInstanceBlockEntity blockEntity2 = (TestInstanceBlockEntity)blockEntity;
|
|
if (!blockEntity2.exportTest(source::sendSystemMessage)) {
|
|
allGood = false;
|
|
}
|
|
++count;
|
|
continue;
|
|
}
|
|
throw TEST_INSTANCE_COULD_NOT_BE_FOUND.create();
|
|
}
|
|
if (count == 0) {
|
|
throw NO_STRUCTURES_TO_EXPORT.create();
|
|
}
|
|
String message = "Exported " + count + " structures";
|
|
finder.source().sendSuccess(() -> Component.literal(message), true);
|
|
return allGood ? 0 : 1;
|
|
}
|
|
|
|
private static int verify(TestFinder finder) {
|
|
TestCommand.stopTests();
|
|
CommandSourceStack source = finder.source();
|
|
ServerLevel level = source.getLevel();
|
|
BlockPos testPos = TestCommand.createTestPositionAround(source);
|
|
List<GameTestInfo> infos = Stream.concat(TestCommand.toGameTestInfos(source, RetryOptions.noRetries(), finder), TestCommand.toGameTestInfo(source, RetryOptions.noRetries(), finder, 0)).toList();
|
|
FailedTestTracker.forgetFailedTests();
|
|
ArrayList<GameTestBatch> batches = new ArrayList<GameTestBatch>();
|
|
for (GameTestInfo info : infos) {
|
|
for (Rotation rotation : Rotation.values()) {
|
|
ArrayList<GameTestInfo> transformedInfos = new ArrayList<GameTestInfo>();
|
|
for (int i = 0; i < 100; ++i) {
|
|
GameTestInfo copyInfo = new GameTestInfo(info.getTestHolder(), rotation, level, new RetryOptions(1, true));
|
|
copyInfo.setTestBlockPos(info.getTestBlockPos());
|
|
transformedInfos.add(copyInfo);
|
|
}
|
|
GameTestBatch batch = GameTestBatchFactory.toGameTestBatch(transformedInfos, info.getTest().batch(), rotation.ordinal());
|
|
batches.add(batch);
|
|
}
|
|
}
|
|
StructureGridSpawner spawner = new StructureGridSpawner(testPos, 10, true);
|
|
GameTestRunner runner = GameTestRunner.Builder.fromBatches(batches, level).batcher(GameTestBatchFactory.fromGameTestInfo(100)).newStructureSpawner(spawner).existingStructureSpawner(spawner).haltOnError().clearBetweenBatches().build();
|
|
return TestCommand.trackAndStartRunner(source, runner);
|
|
}
|
|
|
|
private static int run(TestFinder finder, RetryOptions retryOptions, int extraRotationSteps, int testsPerRow) {
|
|
TestCommand.stopTests();
|
|
CommandSourceStack source = finder.source();
|
|
ServerLevel level = source.getLevel();
|
|
BlockPos testPos = TestCommand.createTestPositionAround(source);
|
|
List<GameTestInfo> infos = Stream.concat(TestCommand.toGameTestInfos(source, retryOptions, finder), TestCommand.toGameTestInfo(source, retryOptions, finder, extraRotationSteps)).toList();
|
|
if (infos.isEmpty()) {
|
|
source.sendSuccess(() -> Component.translatable("commands.test.no_tests"), false);
|
|
return 0;
|
|
}
|
|
FailedTestTracker.forgetFailedTests();
|
|
source.sendSuccess(() -> Component.translatable("commands.test.run.running", infos.size()), false);
|
|
GameTestRunner runner = GameTestRunner.Builder.fromInfo(infos, level).newStructureSpawner(new StructureGridSpawner(testPos, testsPerRow, false)).build();
|
|
return TestCommand.trackAndStartRunner(source, runner);
|
|
}
|
|
|
|
private static int locate(TestFinder finder) throws CommandSyntaxException {
|
|
finder.source().sendSystemMessage(Component.translatable("commands.test.locate.started"));
|
|
MutableInt structuresFound = new MutableInt(0);
|
|
BlockPos sourcePos = BlockPos.containing(finder.source().getPosition());
|
|
finder.findTestPos().forEach(structurePos -> {
|
|
BlockEntity patt0$temp = finder.source().getLevel().getBlockEntity((BlockPos)structurePos);
|
|
if (!(patt0$temp instanceof TestInstanceBlockEntity)) {
|
|
return;
|
|
}
|
|
TestInstanceBlockEntity testBlock = (TestInstanceBlockEntity)patt0$temp;
|
|
Direction facingDirection = testBlock.getRotation().rotate(Direction.NORTH);
|
|
BlockPos telportPosition = testBlock.getBlockPos().relative(facingDirection, 2);
|
|
int teleportYRot = (int)facingDirection.getOpposite().toYRot();
|
|
String tpCommand = String.format(Locale.ROOT, "/tp @s %d %d %d %d 0", telportPosition.getX(), telportPosition.getY(), telportPosition.getZ(), teleportYRot);
|
|
int dx = sourcePos.getX() - structurePos.getX();
|
|
int dz = sourcePos.getZ() - structurePos.getZ();
|
|
int distance = Mth.floor(Mth.sqrt(dx * dx + dz * dz));
|
|
MutableComponent coordinates = ComponentUtils.wrapInSquareBrackets(Component.translatable("chat.coordinates", structurePos.getX(), structurePos.getY(), structurePos.getZ())).withStyle(s -> s.withColor(ChatFormatting.GREEN).withClickEvent(new ClickEvent.SuggestCommand(tpCommand)).withHoverEvent(new HoverEvent.ShowText(Component.translatable("chat.coordinates.tooltip"))));
|
|
finder.source().sendSuccess(() -> Component.translatable("commands.test.locate.found", coordinates, distance), false);
|
|
structuresFound.increment();
|
|
});
|
|
int structures = structuresFound.intValue();
|
|
if (structures == 0) {
|
|
throw NO_TEST_INSTANCES.create();
|
|
}
|
|
finder.source().sendSuccess(() -> Component.translatable("commands.test.locate.done", structures), true);
|
|
return structures;
|
|
}
|
|
|
|
private static ArgumentBuilder<CommandSourceStack, ?> runWithRetryOptions(ArgumentBuilder<CommandSourceStack, ?> runArgument, InCommandFunction<CommandContext<CommandSourceStack>, TestFinder> finder, Function<ArgumentBuilder<CommandSourceStack, ?>, ArgumentBuilder<CommandSourceStack, ?>> then) {
|
|
return runArgument.executes(c -> TestCommand.run((TestFinder)finder.apply(c), RetryOptions.noRetries(), 0, 8)).then(((RequiredArgumentBuilder)Commands.argument("numberOfTimes", IntegerArgumentType.integer((int)0)).executes(c -> TestCommand.run((TestFinder)finder.apply(c), new RetryOptions(IntegerArgumentType.getInteger((CommandContext)c, (String)"numberOfTimes"), false), 0, 8))).then(then.apply(Commands.argument("untilFailed", BoolArgumentType.bool()).executes(c -> TestCommand.run((TestFinder)finder.apply(c), new RetryOptions(IntegerArgumentType.getInteger((CommandContext)c, (String)"numberOfTimes"), BoolArgumentType.getBool((CommandContext)c, (String)"untilFailed")), 0, 8)))));
|
|
}
|
|
|
|
private static ArgumentBuilder<CommandSourceStack, ?> runWithRetryOptions(ArgumentBuilder<CommandSourceStack, ?> runArgument, InCommandFunction<CommandContext<CommandSourceStack>, TestFinder> finder) {
|
|
return TestCommand.runWithRetryOptions(runArgument, finder, a -> a);
|
|
}
|
|
|
|
private static ArgumentBuilder<CommandSourceStack, ?> runWithRetryOptionsAndBuildInfo(ArgumentBuilder<CommandSourceStack, ?> runArgument, InCommandFunction<CommandContext<CommandSourceStack>, TestFinder> finder) {
|
|
return TestCommand.runWithRetryOptions(runArgument, finder, then -> then.then(((RequiredArgumentBuilder)Commands.argument("rotationSteps", IntegerArgumentType.integer()).executes(c -> TestCommand.run((TestFinder)finder.apply(c), new RetryOptions(IntegerArgumentType.getInteger((CommandContext)c, (String)"numberOfTimes"), BoolArgumentType.getBool((CommandContext)c, (String)"untilFailed")), IntegerArgumentType.getInteger((CommandContext)c, (String)"rotationSteps"), 8))).then(Commands.argument("testsPerRow", IntegerArgumentType.integer()).executes(c -> TestCommand.run((TestFinder)finder.apply(c), new RetryOptions(IntegerArgumentType.getInteger((CommandContext)c, (String)"numberOfTimes"), BoolArgumentType.getBool((CommandContext)c, (String)"untilFailed")), IntegerArgumentType.getInteger((CommandContext)c, (String)"rotationSteps"), IntegerArgumentType.getInteger((CommandContext)c, (String)"testsPerRow"))))));
|
|
}
|
|
|
|
public static void register(CommandDispatcher<CommandSourceStack> dispatcher, CommandBuildContext context) {
|
|
ArgumentBuilder<CommandSourceStack, ?> runFailedWithRequiredTestsFlag = TestCommand.runWithRetryOptionsAndBuildInfo(Commands.argument("onlyRequiredTests", BoolArgumentType.bool()), c -> TestFinder.builder().failedTests((CommandContext<CommandSourceStack>)c, BoolArgumentType.getBool((CommandContext)c, (String)"onlyRequiredTests")));
|
|
LiteralArgumentBuilder testCommand = (LiteralArgumentBuilder)((LiteralArgumentBuilder)((LiteralArgumentBuilder)((LiteralArgumentBuilder)((LiteralArgumentBuilder)((LiteralArgumentBuilder)((LiteralArgumentBuilder)((LiteralArgumentBuilder)((LiteralArgumentBuilder)((LiteralArgumentBuilder)((LiteralArgumentBuilder)((LiteralArgumentBuilder)((LiteralArgumentBuilder)((LiteralArgumentBuilder)((LiteralArgumentBuilder)((LiteralArgumentBuilder)((LiteralArgumentBuilder)((LiteralArgumentBuilder)Commands.literal("test").requires(Commands.hasPermission(Commands.LEVEL_GAMEMASTERS))).then(Commands.literal("run").then(TestCommand.runWithRetryOptionsAndBuildInfo(Commands.argument("tests", ResourceSelectorArgument.resourceSelector(context, Registries.TEST_INSTANCE)), c -> TestFinder.builder().byResourceSelection((CommandContext<CommandSourceStack>)c, ResourceSelectorArgument.getSelectedResources((CommandContext<CommandSourceStack>)c, "tests")))))).then(Commands.literal("runmultiple").then(((RequiredArgumentBuilder)Commands.argument("tests", ResourceSelectorArgument.resourceSelector(context, Registries.TEST_INSTANCE)).executes(c -> TestCommand.run(TestFinder.builder().byResourceSelection((CommandContext<CommandSourceStack>)c, ResourceSelectorArgument.getSelectedResources((CommandContext<CommandSourceStack>)c, "tests")), RetryOptions.noRetries(), 0, 8))).then(Commands.argument("amount", IntegerArgumentType.integer()).executes(c -> TestCommand.run(TestFinder.builder().createMultipleCopies(IntegerArgumentType.getInteger((CommandContext)c, (String)"amount")).byResourceSelection((CommandContext<CommandSourceStack>)c, ResourceSelectorArgument.getSelectedResources((CommandContext<CommandSourceStack>)c, "tests")), RetryOptions.noRetries(), 0, 8)))))).then(TestCommand.runWithRetryOptions(Commands.literal("runthese"), TestFinder.builder()::allNearby))).then(TestCommand.runWithRetryOptions(Commands.literal("runclosest"), TestFinder.builder()::nearest))).then(TestCommand.runWithRetryOptions(Commands.literal("runthat"), TestFinder.builder()::lookedAt))).then(TestCommand.runWithRetryOptionsAndBuildInfo(Commands.literal("runfailed").then(runFailedWithRequiredTestsFlag), TestFinder.builder()::failedTests))).then(Commands.literal("verify").then(Commands.argument("tests", ResourceSelectorArgument.resourceSelector(context, Registries.TEST_INSTANCE)).executes(c -> TestCommand.verify(TestFinder.builder().byResourceSelection((CommandContext<CommandSourceStack>)c, ResourceSelectorArgument.getSelectedResources((CommandContext<CommandSourceStack>)c, "tests"))))))).then(Commands.literal("locate").then(Commands.argument("tests", ResourceSelectorArgument.resourceSelector(context, Registries.TEST_INSTANCE)).executes(c -> TestCommand.locate(TestFinder.builder().byResourceSelection((CommandContext<CommandSourceStack>)c, ResourceSelectorArgument.getSelectedResources((CommandContext<CommandSourceStack>)c, "tests"))))))).then(Commands.literal("resetclosest").executes(c -> TestCommand.reset(TestFinder.builder().nearest((CommandContext<CommandSourceStack>)c))))).then(Commands.literal("resetthese").executes(c -> TestCommand.reset(TestFinder.builder().allNearby((CommandContext<CommandSourceStack>)c))))).then(Commands.literal("resetthat").executes(c -> TestCommand.reset(TestFinder.builder().lookedAt((CommandContext<CommandSourceStack>)c))))).then(Commands.literal("clearthat").executes(c -> TestCommand.clear(TestFinder.builder().lookedAt((CommandContext<CommandSourceStack>)c))))).then(Commands.literal("clearthese").executes(c -> TestCommand.clear(TestFinder.builder().allNearby((CommandContext<CommandSourceStack>)c))))).then(((LiteralArgumentBuilder)Commands.literal("clearall").executes(c -> TestCommand.clear(TestFinder.builder().radius((CommandContext<CommandSourceStack>)c, 250)))).then(Commands.argument("radius", IntegerArgumentType.integer()).executes(c -> TestCommand.clear(TestFinder.builder().radius((CommandContext<CommandSourceStack>)c, Mth.clamp(IntegerArgumentType.getInteger((CommandContext)c, (String)"radius"), 0, 1024))))))).then(Commands.literal("stop").executes(c -> TestCommand.stopTests()))).then(((LiteralArgumentBuilder)Commands.literal("pos").executes(c -> TestCommand.showPos((CommandSourceStack)c.getSource(), "pos"))).then(Commands.argument("var", StringArgumentType.word()).executes(c -> TestCommand.showPos((CommandSourceStack)c.getSource(), StringArgumentType.getString((CommandContext)c, (String)"var")))))).then(Commands.literal("create").then(((RequiredArgumentBuilder)Commands.argument("id", IdentifierArgument.id()).suggests(TestCommand::suggestTestFunction).executes(c -> TestCommand.createNewStructure((CommandSourceStack)c.getSource(), IdentifierArgument.getId((CommandContext<CommandSourceStack>)c, "id"), 5, 5, 5))).then(((RequiredArgumentBuilder)Commands.argument("width", IntegerArgumentType.integer()).executes(c -> TestCommand.createNewStructure((CommandSourceStack)c.getSource(), IdentifierArgument.getId((CommandContext<CommandSourceStack>)c, "id"), IntegerArgumentType.getInteger((CommandContext)c, (String)"width"), IntegerArgumentType.getInteger((CommandContext)c, (String)"width"), IntegerArgumentType.getInteger((CommandContext)c, (String)"width")))).then(Commands.argument("height", IntegerArgumentType.integer()).then(Commands.argument("depth", IntegerArgumentType.integer()).executes(c -> TestCommand.createNewStructure((CommandSourceStack)c.getSource(), IdentifierArgument.getId((CommandContext<CommandSourceStack>)c, "id"), IntegerArgumentType.getInteger((CommandContext)c, (String)"width"), IntegerArgumentType.getInteger((CommandContext)c, (String)"height"), IntegerArgumentType.getInteger((CommandContext)c, (String)"depth"))))))));
|
|
if (SharedConstants.IS_RUNNING_IN_IDE) {
|
|
testCommand = (LiteralArgumentBuilder)((LiteralArgumentBuilder)((LiteralArgumentBuilder)((LiteralArgumentBuilder)testCommand.then(Commands.literal("export").then(Commands.argument("test", ResourceArgument.resource(context, Registries.TEST_INSTANCE)).executes(c -> TestCommand.exportTestStructure((CommandSourceStack)c.getSource(), ResourceArgument.getResource((CommandContext<CommandSourceStack>)c, "test", Registries.TEST_INSTANCE)))))).then(Commands.literal("exportclosest").executes(c -> TestCommand.export(TestFinder.builder().nearest((CommandContext<CommandSourceStack>)c))))).then(Commands.literal("exportthese").executes(c -> TestCommand.export(TestFinder.builder().allNearby((CommandContext<CommandSourceStack>)c))))).then(Commands.literal("exportthat").executes(c -> TestCommand.export(TestFinder.builder().lookedAt((CommandContext<CommandSourceStack>)c))));
|
|
}
|
|
dispatcher.register(testCommand);
|
|
}
|
|
|
|
public static CompletableFuture<Suggestions> suggestTestFunction(CommandContext<CommandSourceStack> context, SuggestionsBuilder builder) {
|
|
Stream<String> testNamesStream = ((CommandSourceStack)context.getSource()).registryAccess().lookupOrThrow(Registries.TEST_FUNCTION).listElements().map(Holder::getRegisteredName);
|
|
return SharedSuggestionProvider.suggest(testNamesStream, builder);
|
|
}
|
|
|
|
private static int resetGameTestInfo(CommandSourceStack source, GameTestInfo testInfo) {
|
|
TestInstanceBlockEntity blockEntity = testInfo.getTestInstanceBlockEntity();
|
|
blockEntity.resetTest(source::sendSystemMessage);
|
|
return 1;
|
|
}
|
|
|
|
private static Stream<GameTestInfo> toGameTestInfos(CommandSourceStack source, RetryOptions retryOptions, TestPosFinder finder) {
|
|
return finder.findTestPos().map(pos -> TestCommand.createGameTestInfo(pos, source, retryOptions)).flatMap(Optional::stream);
|
|
}
|
|
|
|
private static Stream<GameTestInfo> toGameTestInfo(CommandSourceStack source, RetryOptions retryOptions, TestInstanceFinder finder, int rotationSteps) {
|
|
return finder.findTests().filter(test -> TestCommand.verifyStructureExists(source, ((GameTestInstance)test.value()).structure())).map(test -> new GameTestInfo((Holder.Reference<GameTestInstance>)test, StructureUtils.getRotationForRotationSteps(rotationSteps), source.getLevel(), retryOptions));
|
|
}
|
|
|
|
private static Optional<GameTestInfo> createGameTestInfo(BlockPos testBlockPos, CommandSourceStack source, RetryOptions retryOptions) {
|
|
ServerLevel level = source.getLevel();
|
|
BlockEntity blockEntity = level.getBlockEntity(testBlockPos);
|
|
if (!(blockEntity instanceof TestInstanceBlockEntity)) {
|
|
source.sendFailure(Component.translatable("commands.test.error.test_instance_not_found.position", testBlockPos.getX(), testBlockPos.getY(), testBlockPos.getZ()));
|
|
return Optional.empty();
|
|
}
|
|
TestInstanceBlockEntity blockEntity2 = (TestInstanceBlockEntity)blockEntity;
|
|
Optional maybeTest = blockEntity2.test().flatMap(((Registry)source.registryAccess().lookupOrThrow(Registries.TEST_INSTANCE))::get);
|
|
if (maybeTest.isEmpty()) {
|
|
source.sendFailure(Component.translatable("commands.test.error.non_existant_test", blockEntity2.getTestName()));
|
|
return Optional.empty();
|
|
}
|
|
Holder.Reference test = (Holder.Reference)maybeTest.get();
|
|
GameTestInfo testInfo = new GameTestInfo(test, blockEntity2.getRotation(), level, retryOptions);
|
|
testInfo.setTestBlockPos(testBlockPos);
|
|
if (!TestCommand.verifyStructureExists(source, testInfo.getStructure())) {
|
|
return Optional.empty();
|
|
}
|
|
return Optional.of(testInfo);
|
|
}
|
|
|
|
private static int createNewStructure(CommandSourceStack source, Identifier id, int xSize, int ySize, int zSize) throws CommandSyntaxException {
|
|
if (xSize > 48 || ySize > 48 || zSize > 48) {
|
|
throw TOO_LARGE.create((Object)48);
|
|
}
|
|
ServerLevel level = source.getLevel();
|
|
BlockPos testPos = TestCommand.createTestPositionAround(source);
|
|
TestInstanceBlockEntity test = StructureUtils.createNewEmptyTest(id, testPos, new Vec3i(xSize, ySize, zSize), Rotation.NONE, level);
|
|
BlockPos low = test.getStructurePos();
|
|
BlockPos high = low.offset(xSize - 1, 0, zSize - 1);
|
|
BlockPos.betweenClosedStream(low, high).forEach(blockPos -> level.setBlockAndUpdate((BlockPos)blockPos, Blocks.BEDROCK.defaultBlockState()));
|
|
source.sendSuccess(() -> Component.translatable("commands.test.create.success", test.getTestName()), true);
|
|
return 1;
|
|
}
|
|
|
|
private static int showPos(CommandSourceStack source, String varName) throws CommandSyntaxException {
|
|
ServerLevel level;
|
|
ServerPlayer player = source.getPlayerOrException();
|
|
BlockHitResult pick = (BlockHitResult)player.pick(10.0, 1.0f, false);
|
|
BlockPos targetPosAbsolute = pick.getBlockPos();
|
|
Optional<BlockPos> testBlockPos = StructureUtils.findTestContainingPos(targetPosAbsolute, 15, level = source.getLevel());
|
|
if (testBlockPos.isEmpty()) {
|
|
testBlockPos = StructureUtils.findTestContainingPos(targetPosAbsolute, 250, level);
|
|
}
|
|
if (testBlockPos.isEmpty()) {
|
|
throw NO_TEST_CONTAINING.create((Object)targetPosAbsolute.getX(), (Object)targetPosAbsolute.getY(), (Object)targetPosAbsolute.getZ());
|
|
}
|
|
BlockEntity blockEntity = level.getBlockEntity(testBlockPos.get());
|
|
if (!(blockEntity instanceof TestInstanceBlockEntity)) {
|
|
throw TEST_INSTANCE_COULD_NOT_BE_FOUND.create();
|
|
}
|
|
TestInstanceBlockEntity testBlockEntity = (TestInstanceBlockEntity)blockEntity;
|
|
BlockPos testOrigin = testBlockEntity.getStructurePos();
|
|
BlockPos targetPosRelative = targetPosAbsolute.subtract(testOrigin);
|
|
String targetPosDescription = targetPosRelative.getX() + ", " + targetPosRelative.getY() + ", " + targetPosRelative.getZ();
|
|
String testName = testBlockEntity.getTestName().getString();
|
|
MutableComponent coords = Component.translatable("commands.test.coordinates", targetPosRelative.getX(), targetPosRelative.getY(), targetPosRelative.getZ()).setStyle(Style.EMPTY.withBold(true).withColor(ChatFormatting.GREEN).withHoverEvent(new HoverEvent.ShowText(Component.translatable("commands.test.coordinates.copy"))).withClickEvent(new ClickEvent.CopyToClipboard("final BlockPos " + varName + " = new BlockPos(" + targetPosDescription + ");")));
|
|
source.sendSuccess(() -> Component.translatable("commands.test.relative_position", testName, coords), false);
|
|
player.connection.send(new ClientboundGameTestHighlightPosPacket(targetPosAbsolute, targetPosRelative));
|
|
return 1;
|
|
}
|
|
|
|
private static int stopTests() {
|
|
GameTestTicker.SINGLETON.clear();
|
|
return 1;
|
|
}
|
|
|
|
public static int trackAndStartRunner(CommandSourceStack source, GameTestRunner runner) {
|
|
runner.addListener(new TestBatchSummaryDisplayer(source));
|
|
MultipleTestTracker tracker = new MultipleTestTracker(runner.getTestInfos());
|
|
tracker.addListener(new TestSummaryDisplayer(source, tracker));
|
|
tracker.addFailureListener(testInfo -> FailedTestTracker.rememberFailedTest(testInfo.getTestHolder()));
|
|
runner.start();
|
|
return 1;
|
|
}
|
|
|
|
private static int exportTestStructure(CommandSourceStack source, Holder<GameTestInstance> test) {
|
|
if (!TestInstanceBlockEntity.export(source.getLevel(), test.value().structure(), source::sendSystemMessage)) {
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
private static boolean verifyStructureExists(CommandSourceStack source, Identifier structure) {
|
|
if (source.getLevel().getStructureManager().get(structure).isEmpty()) {
|
|
source.sendFailure(Component.translatable("commands.test.error.structure_not_found", Component.translationArg(structure)));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private static BlockPos createTestPositionAround(CommandSourceStack source) {
|
|
BlockPos playerPos = BlockPos.containing(source.getPosition());
|
|
int surfaceY = source.getLevel().getHeightmapPos(Heightmap.Types.WORLD_SURFACE, playerPos).getY();
|
|
return new BlockPos(playerPos.getX(), surfaceY, playerPos.getZ() + 3);
|
|
}
|
|
|
|
private record TestBatchSummaryDisplayer(CommandSourceStack source) implements GameTestBatchListener
|
|
{
|
|
@Override
|
|
public void testBatchStarting(GameTestBatch batch) {
|
|
this.source.sendSuccess(() -> Component.translatable("commands.test.batch.starting", batch.environment().getRegisteredName(), batch.index()), true);
|
|
}
|
|
|
|
@Override
|
|
public void testBatchFinished(GameTestBatch batch) {
|
|
}
|
|
}
|
|
|
|
public record TestSummaryDisplayer(CommandSourceStack source, MultipleTestTracker tracker) implements GameTestListener
|
|
{
|
|
@Override
|
|
public void testStructureLoaded(GameTestInfo testInfo) {
|
|
}
|
|
|
|
@Override
|
|
public void testPassed(GameTestInfo testInfo, GameTestRunner runner) {
|
|
this.showTestSummaryIfAllDone();
|
|
}
|
|
|
|
@Override
|
|
public void testFailed(GameTestInfo testInfo, GameTestRunner runner) {
|
|
this.showTestSummaryIfAllDone();
|
|
}
|
|
|
|
@Override
|
|
public void testAddedForRerun(GameTestInfo original, GameTestInfo copy, GameTestRunner runner) {
|
|
this.tracker.addTestToTrack(copy);
|
|
}
|
|
|
|
private void showTestSummaryIfAllDone() {
|
|
if (this.tracker.isDone()) {
|
|
this.source.sendSuccess(() -> Component.translatable("commands.test.summary", this.tracker.getTotalCount()).withStyle(ChatFormatting.WHITE), true);
|
|
if (this.tracker.hasFailedRequired()) {
|
|
this.source.sendFailure(Component.translatable("commands.test.summary.failed", this.tracker.getFailedRequiredCount()));
|
|
} else {
|
|
this.source.sendSuccess(() -> Component.translatable("commands.test.summary.all_required_passed").withStyle(ChatFormatting.GREEN), true);
|
|
}
|
|
if (this.tracker.hasFailedOptional()) {
|
|
this.source.sendSystemMessage(Component.translatable("commands.test.summary.optional_failed", this.tracker.getFailedOptionalCount()));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|