From 125ec113dcf2f334175a365e2cec5127fcd58604 Mon Sep 17 00:00:00 2001 From: mworzala Date: Tue, 6 Feb 2024 22:19:03 -0500 Subject: [PATCH] feat: remove FakePlayer --- .../net/minestom/server/entity/Player.java | 4 +- .../server/entity/fakeplayer/FakePlayer.java | 170 -------------- .../fakeplayer/FakePlayerController.java | 215 ------------------ .../entity/fakeplayer/FakePlayerOption.java | 56 ----- .../network/player/FakePlayerConnection.java | 39 ---- 5 files changed, 1 insertion(+), 483 deletions(-) delete mode 100644 src/main/java/net/minestom/server/entity/fakeplayer/FakePlayer.java delete mode 100644 src/main/java/net/minestom/server/entity/fakeplayer/FakePlayerController.java delete mode 100644 src/main/java/net/minestom/server/entity/fakeplayer/FakePlayerOption.java delete mode 100644 src/main/java/net/minestom/server/network/player/FakePlayerConnection.java diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index 08bd990fdb4..d26301254df 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -32,7 +32,6 @@ import net.minestom.server.coordinate.Vec; import net.minestom.server.effects.Effects; import net.minestom.server.entity.damage.DamageType; -import net.minestom.server.entity.fakeplayer.FakePlayer; import net.minestom.server.entity.metadata.LivingEntityMeta; import net.minestom.server.entity.metadata.PlayerMeta; import net.minestom.server.entity.vehicle.PlayerVehicleInformation; @@ -111,8 +110,7 @@ import java.util.function.UnaryOperator; /** - * Those are the major actors of the server, - * they are not necessary backed by a {@link PlayerSocketConnection} as shown by {@link FakePlayer}. + * Those are the major actors of the server *

* You can easily create your own implementation of this and use it with {@link ConnectionManager#setPlayerProvider(PlayerProvider)}. */ diff --git a/src/main/java/net/minestom/server/entity/fakeplayer/FakePlayer.java b/src/main/java/net/minestom/server/entity/fakeplayer/FakePlayer.java deleted file mode 100644 index d7487a4f4e3..00000000000 --- a/src/main/java/net/minestom/server/entity/fakeplayer/FakePlayer.java +++ /dev/null @@ -1,170 +0,0 @@ -package net.minestom.server.entity.fakeplayer; - -import com.extollit.gaming.ai.path.HydrazinePathFinder; -import net.minestom.server.MinecraftServer; -import net.minestom.server.coordinate.Pos; -import net.minestom.server.entity.Player; -import net.minestom.server.entity.pathfinding.NavigableEntity; -import net.minestom.server.entity.pathfinding.Navigator; -import net.minestom.server.event.EventListener; -import net.minestom.server.event.player.PlayerSpawnEvent; -import net.minestom.server.instance.Instance; -import net.minestom.server.listener.manager.PacketListenerManager; -import net.minestom.server.network.ConnectionManager; -import net.minestom.server.network.ConnectionState; -import net.minestom.server.network.packet.client.login.ClientLoginAcknowledgedPacket; -import net.minestom.server.network.player.FakePlayerConnection; -import net.minestom.server.network.player.PlayerConnection; -import net.minestom.server.utils.time.TimeUnit; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.function.Consumer; - -/** - * A fake player will behave exactly the same way as would do a {@link Player} backed by a socket connection - * (events, velocity, gravity, player list, etc...) with the exception that you need to control it server-side - * using a {@link FakePlayerController} (see {@link #getController()}). - *

- * You can create one using {@link #initPlayer(UUID, String, Consumer)}. Be aware that this really behave exactly like a player - * and this is a feature not a bug, you will need to check at some place if the player is a fake one or not (instanceof) if you want to change it. - */ -public class FakePlayer extends Player implements NavigableEntity { - - private static final ConnectionManager CONNECTION_MANAGER = MinecraftServer.getConnectionManager(); - private static final PacketListenerManager PACKET_LISTENER_MANAGER = MinecraftServer.getPacketListenerManager(); - - private final FakePlayerOption option; - private final FakePlayerController fakePlayerController; - - private final Navigator navigator = new Navigator(this); - - private EventListener spawnListener; - - /** - * Initializes a new {@link FakePlayer} with the given {@code uuid}, {@code username} and {@code option}'s. - * - * @param uuid The unique identifier for the fake player. - * @param username The username for the fake player. - * @param option Any option for the fake player. - */ - protected FakePlayer(@NotNull UUID uuid, @NotNull String username, - @NotNull FakePlayerOption option, - @Nullable Consumer spawnCallback) { - super(uuid, username, new FakePlayerConnection()); - - this.option = option; - - this.fakePlayerController = new FakePlayerController(this); - - if (spawnCallback != null) { - spawnListener = EventListener.builder(PlayerSpawnEvent.class) - .expireWhen(ignored -> this.isRemoved()) - .handler(event -> { - if (event.getPlayer().equals(this)) - if (event.isFirstSpawn()) { - spawnCallback.accept(this); - MinecraftServer.getGlobalEventHandler().removeListener(spawnListener); - } - }).build(); - MinecraftServer.getGlobalEventHandler().addListener(spawnListener); - } - - playerConnection.setConnectionState(ConnectionState.LOGIN); - CONNECTION_MANAGER.transitionLoginToConfig(this).thenRun(() -> { - // Need to immediately reply with login acknowledged for the player to enter config. - PACKET_LISTENER_MANAGER.processClientPacket(new ClientLoginAcknowledgedPacket(), getPlayerConnection()); - }); - } - - /** - * Initializes a new {@link FakePlayer}. - * - * @param uuid the FakePlayer uuid - * @param username the FakePlayer username - * @param spawnCallback the optional callback called when the fake player first spawn - */ - public static void initPlayer(@NotNull UUID uuid, @NotNull String username, - @NotNull FakePlayerOption option, @Nullable Consumer spawnCallback) { - new FakePlayer(uuid, username, option, spawnCallback); - } - - /** - * Initializes a new {@link FakePlayer} without adding it in cache. - *

- * If you want the fake player to be obtainable with the {@link net.minestom.server.network.ConnectionManager} - * you need to specify it in a {@link FakePlayerOption} and use {@link #initPlayer(UUID, String, FakePlayerOption, Consumer)}. - * - * @param uuid the FakePlayer uuid - * @param username the FakePlayer username - * @param spawnCallback the optional callback called when the fake player first spawn - */ - public static void initPlayer(@NotNull UUID uuid, @NotNull String username, @Nullable Consumer spawnCallback) { - initPlayer(uuid, username, new FakePlayerOption(), spawnCallback); - } - - /** - * Gets the fake player option container. - * - * @return the fake player option - */ - @NotNull - public FakePlayerOption getOption() { - return option; - } - - /** - * Retrieves the controller for the fake player. - * - * @return The fake player's controller. - */ - @NotNull - public FakePlayerController getController() { - return fakePlayerController; - } - - @Override - public void update(long time) { - super.update(time); - // Path finding - this.navigator.tick(); - } - - @Override - public CompletableFuture setInstance(@NotNull Instance instance, @NotNull Pos spawnPosition) { - this.navigator.setPathFinder(new HydrazinePathFinder(navigator.getPathingEntity(), instance.getInstanceSpace())); - - return super.setInstance(instance, spawnPosition); - } - - @Override - public void updateNewViewer(@NotNull Player player) { - player.sendPacket(getAddPlayerToList()); - handleTabList(player.getPlayerConnection()); - super.updateNewViewer(player); - } - - /** - * {@inheritDoc} - */ - @Override - protected void showPlayer(@NotNull PlayerConnection connection) { - super.showPlayer(connection); - handleTabList(connection); - } - - @NotNull - @Override - public Navigator getNavigator() { - return navigator; - } - - private void handleTabList(PlayerConnection connection) { - if (!option.isInTabList()) { - // Remove from tab-list - MinecraftServer.getSchedulerManager().buildTask(() -> connection.sendPacket(getRemovePlayerToList())).delay(20, TimeUnit.SERVER_TICK).schedule(); - } - } -} diff --git a/src/main/java/net/minestom/server/entity/fakeplayer/FakePlayerController.java b/src/main/java/net/minestom/server/entity/fakeplayer/FakePlayerController.java deleted file mode 100644 index a05d589aaa8..00000000000 --- a/src/main/java/net/minestom/server/entity/fakeplayer/FakePlayerController.java +++ /dev/null @@ -1,215 +0,0 @@ -package net.minestom.server.entity.fakeplayer; - -import net.minestom.server.coordinate.Point; -import net.minestom.server.entity.Entity; -import net.minestom.server.entity.Player; -import net.minestom.server.instance.block.BlockFace; -import net.minestom.server.inventory.AbstractInventory; -import net.minestom.server.inventory.Inventory; -import net.minestom.server.inventory.PlayerInventory; -import net.minestom.server.item.ItemStack; -import net.minestom.server.network.packet.client.ClientPacket; -import net.minestom.server.network.packet.client.common.ClientKeepAlivePacket; -import net.minestom.server.network.packet.client.common.ClientPluginMessagePacket; -import net.minestom.server.network.packet.client.configuration.ClientFinishConfigurationPacket; -import net.minestom.server.network.packet.client.play.*; -import net.minestom.server.network.packet.server.SendablePacket; -import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.common.KeepAlivePacket; -import net.minestom.server.network.packet.server.configuration.FinishConfigurationPacket; -import net.minestom.server.network.packet.server.play.PlayerPositionAndLookPacket; -import net.minestom.server.network.player.PlayerConnection; -import net.minestom.server.utils.MathUtils; -import net.minestom.server.utils.inventory.PlayerInventoryUtils; -import net.minestom.server.utils.validate.Check; -import org.jetbrains.annotations.NotNull; - -import java.util.List; - -/** - * This class acts as a client controller for {@link FakePlayer}. - *

- * The main use is to simulate the receiving of {@link ClientPacket} - */ -public class FakePlayerController { - - private final FakePlayer fakePlayer; - - /** - * Initializes a new {@link FakePlayerController} with the given {@link FakePlayer}. - * - * @param fakePlayer The fake player that should used the controller. - */ - public FakePlayerController(@NotNull FakePlayer fakePlayer) { - this.fakePlayer = fakePlayer; - } - - /** - * Simulates a click in a window. - * - * @param playerInventory {@code true} if the window a {@link PlayerInventory}, otherwise {@code false}. - * @param slot The slot where the fake player should click on. - * @param button The mouse button that the fake player should used. - * @param clickType The click type - */ - public void clickWindow(boolean playerInventory, short slot, byte button, ClientClickWindowPacket.ClickType clickType) { - Inventory inventory = playerInventory ? null : fakePlayer.getOpenInventory(); - AbstractInventory abstractInventory = inventory == null ? fakePlayer.getInventory() : inventory; - playerInventory = abstractInventory instanceof PlayerInventory; - - slot = playerInventory ? (short) PlayerInventoryUtils.convertToPacketSlot(slot) : slot; - - ItemStack itemStack = abstractInventory.getItemStack(slot); - - addToQueue(new ClientClickWindowPacket(playerInventory ? 0 : inventory.getWindowId(), 0, - slot, button, clickType, - List.of(), itemStack)); - } - - /** - * Closes the current opened inventory if there is any. - */ - public void closeWindow() { - Inventory openInventory = fakePlayer.getOpenInventory(); - addToQueue(new ClientCloseWindowPacket(openInventory == null ? 0 : openInventory.getWindowId())); - } - - /** - * Sends a plugin message to the player. - * - * @param channel The channel of the message. - * @param message The message data. - */ - public void sendPluginMessage(String channel, byte[] message) { - addToQueue(new ClientPluginMessagePacket(channel, message)); - } - - /** - * Sends a plugin message to the player. - * - * @param channel The channel of the message. - * @param message The message data. - */ - public void sendPluginMessage(String channel, String message) { - sendPluginMessage(channel, message.getBytes()); - } - - /** - * Attacks the given {@code entity}. - * - * @param entity The entity that is to be attacked. - */ - public void attackEntity(Entity entity) { - addToQueue(new ClientInteractEntityPacket(entity.getEntityId(), new ClientInteractEntityPacket.Attack(), fakePlayer.isSneaking())); - } - - /** - * Respawns the player. - * - * @see Player#respawn() - */ - public void respawn() { - // Sending the respawn packet for some reason - // Is related to FakePlayer#showPlayer and the tablist option (probably because of the scheduler) - /*ClientStatusPacket statusPacket = new ClientStatusPacket(); - statusPacket.action = ClientStatusPacket.Action.PERFORM_RESPAWN; - addToQueue(statusPacket);*/ - fakePlayer.respawn(); - } - - /** - * Changes the current held slot for the player. - * - * @param slot The slot that the player has to held. - * @throws IllegalArgumentException If {@code slot} is not between {@code 0} and {@code 8}. - */ - public void setHeldItem(short slot) { - Check.argCondition(!MathUtils.isBetween(slot, 0, 8), "Slot has to be between 0 and 8!"); - addToQueue(new ClientHeldItemChangePacket(slot)); - } - - /** - * Sends an animation packet that animates the specified arm. - * - * @param hand The hand of the arm to be animated. - */ - public void sendArmAnimation(Player.Hand hand) { - addToQueue(new ClientAnimationPacket(hand)); - } - - /** - * Uses the item in the given {@code hand}. - * - * @param hand The hand in which an ite mshould be. - */ - public void useItem(Player.Hand hand) { - addToQueue(new ClientUseItemPacket(hand, 0)); - } - - /** - * Rotates the fake player. - * - * @param yaw The new yaw for the fake player. - * @param pitch The new pitch for the fake player. - */ - public void rotate(float yaw, float pitch) { - addToQueue(new ClientPlayerRotationPacket(yaw, pitch, fakePlayer.isOnGround())); - } - - /** - * Starts the digging process of the fake player. - * - * @param blockPosition The position of the block to be excavated. - * @param blockFace From where the block is struck. - */ - public void startDigging(Point blockPosition, BlockFace blockFace) { - addToQueue(new ClientPlayerDiggingPacket(ClientPlayerDiggingPacket.Status.STARTED_DIGGING, blockPosition, blockFace, 0)); - } - - /** - * Stops the digging process of the fake player. - * - * @param blockPosition The position of the block to be excavated. - * @param blockFace From where the block is struck. - */ - public void stopDigging(Point blockPosition, BlockFace blockFace) { - addToQueue(new ClientPlayerDiggingPacket(ClientPlayerDiggingPacket.Status.CANCELLED_DIGGING, blockPosition, blockFace, 0)); - } - - /** - * Finishes the digging process of the fake player. - * - * @param blockPosition The position of the block to be excavated. - * @param blockFace From where the block is struck. - */ - public void finishDigging(Point blockPosition, BlockFace blockFace) { - addToQueue(new ClientPlayerDiggingPacket(ClientPlayerDiggingPacket.Status.FINISHED_DIGGING, blockPosition, blockFace, 0)); - } - - /** - * Makes the player receives a packet - * WARNING: pretty much unsafe, used internally to redirect packets here, - * you should instead use {@link PlayerConnection#sendPacket(SendablePacket)} - * - * @param serverPacket the packet to consume - */ - public void consumePacket(ServerPacket serverPacket) { - if (serverPacket instanceof PlayerPositionAndLookPacket playerPositionAndLookPacket) { - addToQueue(new ClientTeleportConfirmPacket(playerPositionAndLookPacket.teleportId())); - } else if (serverPacket instanceof KeepAlivePacket keepAlivePacket) { - addToQueue(new ClientKeepAlivePacket(keepAlivePacket.id())); - } else if (serverPacket instanceof FinishConfigurationPacket) { - addToQueue(new ClientFinishConfigurationPacket()); - } - } - - /** - * All packets in the queue are executed in the {@link Player#update(long)} method. It is used internally to add all - * received packet from the client. Could be used to "simulate" a received packet, but to use at your own risk! - * - * @param clientPlayPacket The packet to add in the queue. - */ - private void addToQueue(ClientPacket clientPlayPacket) { - this.fakePlayer.addPacketToQueue(clientPlayPacket); - } -} diff --git a/src/main/java/net/minestom/server/entity/fakeplayer/FakePlayerOption.java b/src/main/java/net/minestom/server/entity/fakeplayer/FakePlayerOption.java deleted file mode 100644 index eacc54218a3..00000000000 --- a/src/main/java/net/minestom/server/entity/fakeplayer/FakePlayerOption.java +++ /dev/null @@ -1,56 +0,0 @@ -package net.minestom.server.entity.fakeplayer; - -import net.minestom.server.network.ConnectionManager; - -/** - * Represents any options for a {@link FakePlayer}. - */ -public class FakePlayerOption { - - private boolean registered = false; - private boolean inTabList = false; - - /** - * Gets if the player is registered internally as a Player. - * - * @return true if the player is registered in {@link ConnectionManager}, false otherwise - */ - public boolean isRegistered() { - return registered; - } - - /** - * Sets the FakePlayer as registered or not. - *

- * WARNING: this can't be changed halfway. - * - * @param registered should the fake player be registered internally - * @return this instance, allowing for chained method calls - */ - public FakePlayerOption setRegistered(boolean registered) { - this.registered = registered; - return this; - } - - /** - * Gets if the player is visible in the tab-list or not. - * - * @return true if the player is in the tab-list, false otherwise - */ - public boolean isInTabList() { - return inTabList; - } - - /** - * Sets the player in the tab-list or not. - *

- * WARNING: this can't be changed halfway. - * - * @param inTabList should the player be in the tab-list - * @return this instance, allowing for chained method calls - */ - public FakePlayerOption setInTabList(boolean inTabList) { - this.inTabList = inTabList; - return this; - } -} diff --git a/src/main/java/net/minestom/server/network/player/FakePlayerConnection.java b/src/main/java/net/minestom/server/network/player/FakePlayerConnection.java deleted file mode 100644 index e498109f407..00000000000 --- a/src/main/java/net/minestom/server/network/player/FakePlayerConnection.java +++ /dev/null @@ -1,39 +0,0 @@ -package net.minestom.server.network.player; - -import net.minestom.server.entity.Player; -import net.minestom.server.entity.fakeplayer.FakePlayer; -import net.minestom.server.entity.fakeplayer.FakePlayerController; -import net.minestom.server.network.packet.server.SendablePacket; -import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.utils.validate.Check; -import org.jetbrains.annotations.NotNull; - -import java.net.InetSocketAddress; -import java.net.SocketAddress; - -public class FakePlayerConnection extends PlayerConnection { - - @Override - public void sendPacket(@NotNull SendablePacket packet) { - FakePlayerController controller = getFakePlayer().getController(); - final ServerPacket serverPacket = SendablePacket.extractServerPacket(getConnectionState(), packet); - controller.consumePacket(serverPacket); - } - - @NotNull - @Override - public SocketAddress getRemoteAddress() { - return new InetSocketAddress(0); - } - - public FakePlayer getFakePlayer() { - return (FakePlayer) getPlayer(); - } - - - @Override - public void setPlayer(Player player) { - Check.argCondition(!(player instanceof FakePlayer), "FakePlayerController needs a FakePlayer object"); - super.setPlayer(player); - } -}