diff --git a/src/main/java/io/github/misode/packtest/PackTest.java b/src/main/java/io/github/misode/packtest/PackTest.java index b5d6982..c9a3f73 100644 --- a/src/main/java/io/github/misode/packtest/PackTest.java +++ b/src/main/java/io/github/misode/packtest/PackTest.java @@ -3,7 +3,7 @@ import io.github.misode.packtest.commands.AssertCommand; import io.github.misode.packtest.commands.FailCommand; import io.github.misode.packtest.commands.SucceedCommand; -import io.github.misode.packtest.commands.PlayerCommand; +import io.github.misode.packtest.commands.DummyCommand; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; import net.minecraft.core.BlockPos; @@ -31,7 +31,7 @@ public void onInitialize() { CommandRegistrationCallback.EVENT.register((dispatcher, buildContext, environment) -> { AssertCommand.register(dispatcher, buildContext); FailCommand.register(dispatcher); - PlayerCommand.register(dispatcher); + DummyCommand.register(dispatcher); SucceedCommand.register(dispatcher, buildContext); }); } diff --git a/src/main/java/io/github/misode/packtest/commands/PlayerCommand.java b/src/main/java/io/github/misode/packtest/commands/DummyCommand.java similarity index 56% rename from src/main/java/io/github/misode/packtest/commands/PlayerCommand.java rename to src/main/java/io/github/misode/packtest/commands/DummyCommand.java index 525b5e0..5f944f7 100644 --- a/src/main/java/io/github/misode/packtest/commands/PlayerCommand.java +++ b/src/main/java/io/github/misode/packtest/commands/DummyCommand.java @@ -7,7 +7,7 @@ import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; -import io.github.misode.packtest.fake.FakePlayer; +import io.github.misode.packtest.dummy.Dummy; import net.minecraft.commands.CommandSourceStack; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; @@ -22,40 +22,40 @@ import static net.minecraft.commands.Commands.argument; import static net.minecraft.commands.Commands.literal; -public class PlayerCommand { +public class DummyCommand { public static void register(CommandDispatcher dispatcher) { - dispatcher.register(literal("player") + dispatcher.register(literal("dummy") .then(literal("spawn") - .executes(PlayerCommand::spawnRandomName) - .then(argument("player", StringArgumentType.word()) - .executes(PlayerCommand::spawnFixedName))) + .executes(DummyCommand::spawnRandomName) + .then(argument("name", StringArgumentType.word()) + .executes(DummyCommand::spawnFixedName))) .then(literal("leave") - .then(playerArgument() - .executes(PlayerCommand::leave))) + .then(dummyName() + .executes(DummyCommand::leave))) .then(literal("respawn") - .then(playerArgument() - .executes(PlayerCommand::respawn))) + .then(dummyName() + .executes(DummyCommand::respawn))) .then(literal("jump") - .then(playerArgument() - .executes(PlayerCommand::jump))) + .then(dummyName() + .executes(DummyCommand::jump))) .then(literal("sneak") - .then(playerArgument() + .then(dummyName() .then(argument("active", BoolArgumentType.bool()) - .executes(PlayerCommand::sneak)))) + .executes(DummyCommand::sneak)))) .then(literal("sprint") - .then(playerArgument() + .then(dummyName() .then(argument("active", BoolArgumentType.bool()) - .executes(PlayerCommand::sprint)))) + .executes(DummyCommand::sprint)))) ); } - private static RequiredArgumentBuilder playerArgument() { - return argument("player", StringArgumentType.word()) + private static RequiredArgumentBuilder dummyName() { + return argument("name", StringArgumentType.word()) .suggests((ctx, builder) -> { PlayerList playerList = ctx.getSource().getServer().getPlayerList(); playerList.getPlayers().forEach(player -> { - if (player instanceof FakePlayer) { + if (player instanceof Dummy) { builder.suggest(player.getName().getString()); } }); @@ -63,16 +63,16 @@ private static RequiredArgumentBuilder playerArgumen }); } - private static FakePlayer getPlayer(CommandContext ctx) throws CommandSyntaxException { - String playerName = StringArgumentType.getString(ctx, "player"); - return getPlayer(playerName, ctx).orElseThrow(() -> new SimpleCommandExceptionType(() -> "Fake player " + playerName + " does not exist").create()); + private static Dummy getDummy(CommandContext ctx) throws CommandSyntaxException { + String playerName = StringArgumentType.getString(ctx, "name"); + return getDummy(playerName, ctx).orElseThrow(() -> new SimpleCommandExceptionType(() -> "Dummy " + playerName + " does not exist").create()); } - private static Optional getPlayer(String playerName, CommandContext ctx) { + private static Optional getDummy(String playerName, CommandContext ctx) { MinecraftServer server = ctx.getSource().getServer(); ServerPlayer player = server.getPlayerList().getPlayerByName(playerName); - if (player instanceof FakePlayer fakePlayer) { - return Optional.of(fakePlayer); + if (player instanceof Dummy testPlayer) { + return Optional.of(testPlayer); } return Optional.empty(); } @@ -81,73 +81,73 @@ private static int spawnRandomName(CommandContext ctx) { int tries = 0; while (tries++ < 10) { RandomSource random = ctx.getSource().getLevel().getRandom(); - String playerName = "Tester" + random.nextInt(100, 1000); - if (getPlayer(playerName, ctx).isEmpty()) { + String playerName = "Dummy" + random.nextInt(100, 1000); + if (getDummy(playerName, ctx).isEmpty()) { return spawn(playerName, ctx); } } - ctx.getSource().sendFailure(Component.literal("Failed to spawn player with a random name")); + ctx.getSource().sendFailure(Component.literal("Failed to spawn dummy with a random name")); return 0; } private static int spawnFixedName(CommandContext ctx) { - String playerName = StringArgumentType.getString(ctx, "player"); + String playerName = StringArgumentType.getString(ctx, "name"); return spawn(playerName, ctx); } - private static int spawn(String playerName, CommandContext ctx) { + private static int spawn(String name, CommandContext ctx) { CommandSourceStack source = ctx.getSource(); MinecraftServer server = source.getServer(); - if (getPlayer(playerName, ctx).isPresent()) { - source.sendFailure(Component.literal("Player " + playerName + " is already logged on")); + if (getDummy(name, ctx).isPresent()) { + source.sendFailure(Component.literal("Dummy " + name + " is already logged on")); return 0; } ResourceKey dimension = source.getLevel().dimension(); - FakePlayer.create(playerName, server, dimension, source.getPosition()); + Dummy.create(name, server, dimension, source.getPosition()); return 1; } private static int leave(CommandContext ctx) throws CommandSyntaxException { - FakePlayer player = getPlayer(ctx); - player.leave(Component.literal("Forced to leave")); + Dummy dummy = getDummy(ctx); + dummy.leave(Component.literal("Forced to leave")); return 1; } private static int respawn(CommandContext ctx) throws CommandSyntaxException { - FakePlayer player = getPlayer(ctx); - player.respawn(); + Dummy dummy = getDummy(ctx); + dummy.respawn(); return 1; } private static int jump(CommandContext ctx) throws CommandSyntaxException { - FakePlayer player = getPlayer(ctx); - if (player.onGround()) { - player.jumpFromGround(); + Dummy dummy = getDummy(ctx); + if (dummy.onGround()) { + dummy.jumpFromGround(); return 1; } - ctx.getSource().sendFailure(Component.literal("Player is not on the ground")); + ctx.getSource().sendFailure(Component.literal("Dummy is not on the ground")); return 0; } private static int sneak(CommandContext ctx) throws CommandSyntaxException { - FakePlayer player = getPlayer(ctx); + Dummy dummy = getDummy(ctx); boolean toggle = BoolArgumentType.getBool(ctx, "active"); - if (player.isShiftKeyDown() != toggle) { - player.setShiftKeyDown(toggle); + if (dummy.isShiftKeyDown() != toggle) { + dummy.setShiftKeyDown(toggle); return 1; } - ctx.getSource().sendFailure(Component.literal(toggle ? "Player is already sneaking" : "Player is already not sneaking")); + ctx.getSource().sendFailure(Component.literal(toggle ? "Dummy is already sneaking" : "Dummy is already not sneaking")); return 0; } private static int sprint(CommandContext ctx) throws CommandSyntaxException { - FakePlayer player = getPlayer(ctx); + Dummy dummy = getDummy(ctx); boolean toggle = BoolArgumentType.getBool(ctx, "active"); - if (player.isSprinting() != toggle) { - player.setSprinting(toggle); + if (dummy.isSprinting() != toggle) { + dummy.setSprinting(toggle); return 1; } - ctx.getSource().sendFailure(Component.literal(toggle ? "Player is already sprinting" : "Player is already not sprinting")); + ctx.getSource().sendFailure(Component.literal(toggle ? "Dummy is already sprinting" : "Dummy is already not sprinting")); return 0; } } diff --git a/src/main/java/io/github/misode/packtest/fake/FakePlayer.java b/src/main/java/io/github/misode/packtest/dummy/Dummy.java similarity index 75% rename from src/main/java/io/github/misode/packtest/fake/FakePlayer.java rename to src/main/java/io/github/misode/packtest/dummy/Dummy.java index 6984fd7..7479cc6 100644 --- a/src/main/java/io/github/misode/packtest/fake/FakePlayer.java +++ b/src/main/java/io/github/misode/packtest/dummy/Dummy.java @@ -1,4 +1,4 @@ -package io.github.misode.packtest.fake; +package io.github.misode.packtest.dummy; import com.mojang.authlib.GameProfile; import net.minecraft.core.BlockPos; @@ -27,7 +27,7 @@ /** * Heavily inspired by Carpet */ -public class FakePlayer extends ServerPlayer { +public class Dummy extends ServerPlayer { public @Nullable BlockPos origin = null; public Runnable fixStartingPosition = () -> {}; @@ -45,23 +45,23 @@ public static void create(String username, MinecraftServer server, ResourceKey instance.moveTo(pos.x, pos.y, pos.z, 0, 0); + Dummy dummy = new Dummy(server, level, profile, ClientInformation.createDefault()); + dummy.origin = BlockPos.containing(pos); + dummy.fixStartingPosition = () -> dummy.moveTo(pos.x, pos.y, pos.z, 0, 0); server.getPlayerList().placeNewPlayer( - new FakeClientConnection(PacketFlow.SERVERBOUND), - instance, - new CommonListenerCookie(profile, 0, instance.clientInformation())); - instance.teleportTo(level, pos.x, pos.y, pos.z, 0, 0); - instance.setHealth(20); - instance.unsetRemoved(); - instance.gameMode.changeGameModeForPlayer(GameType.SURVIVAL); - server.getPlayerList().broadcastAll(new ClientboundRotateHeadPacket(instance, (byte) (instance.yHeadRot * 256 / 360)), dimensionId); - server.getPlayerList().broadcastAll(new ClientboundTeleportEntityPacket(instance), dimensionId); - instance.entityData.set(DATA_PLAYER_MODE_CUSTOMISATION, (byte) 0x7f); + new DummyClientConnection(PacketFlow.SERVERBOUND), + dummy, + new CommonListenerCookie(profile, 0, dummy.clientInformation())); + dummy.teleportTo(level, pos.x, pos.y, pos.z, 0, 0); + dummy.setHealth(20); + dummy.unsetRemoved(); + dummy.gameMode.changeGameModeForPlayer(GameType.SURVIVAL); + server.getPlayerList().broadcastAll(new ClientboundRotateHeadPacket(dummy, (byte) (dummy.yHeadRot * 256 / 360)), dimensionId); + server.getPlayerList().broadcastAll(new ClientboundTeleportEntityPacket(dummy), dimensionId); + dummy.entityData.set(DATA_PLAYER_MODE_CUSTOMISATION, (byte) 0x7f); } - public FakePlayer(MinecraftServer server, ServerLevel level, GameProfile profile, ClientInformation cli) { + public Dummy(MinecraftServer server, ServerLevel level, GameProfile profile, ClientInformation cli) { super(server, level, profile, cli); } diff --git a/src/main/java/io/github/misode/packtest/fake/FakeClientConnection.java b/src/main/java/io/github/misode/packtest/dummy/DummyClientConnection.java similarity index 70% rename from src/main/java/io/github/misode/packtest/fake/FakeClientConnection.java rename to src/main/java/io/github/misode/packtest/dummy/DummyClientConnection.java index c67f2a7..e466aa7 100644 --- a/src/main/java/io/github/misode/packtest/fake/FakeClientConnection.java +++ b/src/main/java/io/github/misode/packtest/dummy/DummyClientConnection.java @@ -1,12 +1,12 @@ -package io.github.misode.packtest.fake; +package io.github.misode.packtest.dummy; import net.minecraft.network.Connection; import net.minecraft.network.PacketListener; import net.minecraft.network.protocol.PacketFlow; -public class FakeClientConnection extends Connection { +public class DummyClientConnection extends Connection { - public FakeClientConnection(PacketFlow flow) { + public DummyClientConnection(PacketFlow flow) { super(flow); } diff --git a/src/main/java/io/github/misode/packtest/mixin/GameTestRunnerMixin.java b/src/main/java/io/github/misode/packtest/mixin/GameTestRunnerMixin.java new file mode 100644 index 0000000..d062a23 --- /dev/null +++ b/src/main/java/io/github/misode/packtest/mixin/GameTestRunnerMixin.java @@ -0,0 +1,30 @@ +package io.github.misode.packtest.mixin; + +import io.github.misode.packtest.dummy.Dummy; +import net.minecraft.core.BlockPos; +import net.minecraft.gametest.framework.GameTestRunner; +import net.minecraft.gametest.framework.GameTestTicker; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.List; + +/** + * Remove all test players when running /test clearall. + */ +@Mixin(GameTestRunner.class) +public class GameTestRunnerMixin { + + @Inject(method = "clearAllTests", at = @At(value = "INVOKE", target = "Lnet/minecraft/core/BlockPos;betweenClosedStream(Lnet/minecraft/core/BlockPos;Lnet/minecraft/core/BlockPos;)Ljava/util/stream/Stream;", shift = At.Shift.AFTER)) + private static void clearTestPlayers(ServerLevel level, BlockPos pos, GameTestTicker ticker, int radius, CallbackInfo ci) { + List testPlayers = level.getServer().getPlayerList().getPlayers().stream() + .filter(p -> p instanceof Dummy && p.distanceToSqr(pos.getCenter()) <= radius) + .map(p -> (Dummy)p) + .toList(); + testPlayers.forEach(p -> p.leave(Component.literal("Cleared tests"))); + } +} diff --git a/src/main/java/io/github/misode/packtest/mixin/PlayerListMixin.java b/src/main/java/io/github/misode/packtest/mixin/PlayerListMixin.java index 3c8949b..bd2b013 100644 --- a/src/main/java/io/github/misode/packtest/mixin/PlayerListMixin.java +++ b/src/main/java/io/github/misode/packtest/mixin/PlayerListMixin.java @@ -4,7 +4,7 @@ import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.llamalad7.mixinextras.sugar.Local; import com.mojang.authlib.GameProfile; -import io.github.misode.packtest.fake.FakePlayer; +import io.github.misode.packtest.dummy.Dummy; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.MinecraftServer; @@ -21,22 +21,22 @@ import java.util.Optional; /** - * Fixes starting position of fake players when they load in. - * Respawns fake players and in the correct position. + * Fixes starting position of test players when they load in. + * Respawns test players and in the correct position. */ @Mixin(PlayerList.class) public class PlayerListMixin { @Inject(method = "load", at = @At(value = "RETURN", shift = At.Shift.BEFORE)) private void fixStartingPos(ServerPlayer player, CallbackInfoReturnable cir) { - if (player instanceof FakePlayer) { - ((FakePlayer) player).fixStartingPosition.run(); + if (player instanceof Dummy) { + ((Dummy) player).fixStartingPosition.run(); } } @WrapOperation(method = "respawn", at = @At(value = "NEW", target = "(Lnet/minecraft/server/MinecraftServer;Lnet/minecraft/server/level/ServerLevel;Lcom/mojang/authlib/GameProfile;Lnet/minecraft/server/level/ClientInformation;)Lnet/minecraft/server/level/ServerPlayer;")) private ServerPlayer createPlayer(MinecraftServer server, ServerLevel level, GameProfile profile, ClientInformation cli, Operation original, @Local(ordinal = 0) ServerPlayer player) { - if (player instanceof FakePlayer) { - return new FakePlayer(server, level, profile, cli); + if (player instanceof Dummy) { + return new Dummy(server, level, profile, cli); } else { return original.call(server, level, profile, cli); } @@ -44,8 +44,8 @@ private ServerPlayer createPlayer(MinecraftServer server, ServerLevel level, Gam @WrapOperation(method = "respawn", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerPlayer;getRespawnPosition()Lnet/minecraft/core/BlockPos;")) private BlockPos getRespawnBlock(ServerPlayer player, Operation original) { - if (player instanceof FakePlayer fakePlayer && fakePlayer.origin != null) { - return fakePlayer.origin; + if (player instanceof Dummy testPlayer && testPlayer.origin != null) { + return testPlayer.origin; } else { return original.call(player); } @@ -53,8 +53,8 @@ private BlockPos getRespawnBlock(ServerPlayer player, Operation origin @WrapOperation(method = "respawn", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;findRespawnPositionAndUseSpawnBlock(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/core/BlockPos;FZZ)Ljava/util/Optional;")) private Optional getRespawnPos(ServerLevel level, BlockPos pos, float angle, boolean forced, boolean other, Operation> original, @Local(ordinal = 0) ServerPlayer player) { - if (player instanceof FakePlayer fakePlayer && fakePlayer.origin != null) { - return Optional.of(new Vec3(fakePlayer.origin.getX() + 0.5, fakePlayer.origin.getY(), fakePlayer.origin.getZ() + 0.5)); + if (player instanceof Dummy testPlayer && testPlayer.origin != null) { + return Optional.of(new Vec3(testPlayer.origin.getX() + 0.5, testPlayer.origin.getY(), testPlayer.origin.getZ() + 0.5)); } else { return original.call(level, pos, angle, forced, other); } diff --git a/src/main/resources/packtest.mixins.json b/src/main/resources/packtest.mixins.json index dc601d8..ef1d7a5 100644 --- a/src/main/resources/packtest.mixins.json +++ b/src/main/resources/packtest.mixins.json @@ -13,6 +13,7 @@ "GameTestHelperMixin", "GameTestInfoMixin", "GameTestRegistryMixin", + "GameTestRunnerMixin", "GameTestServerMixin", "LogTestReporterMixin", "MinecraftServerMixin",