From 44dab9e11b5df5a4ab7852b2906910214f71e15f Mon Sep 17 00:00:00 2001 From: JeremyStarTM Date: Sat, 16 Nov 2024 21:50:28 +0100 Subject: [PATCH] More work on PSPlayer and porting some commands --- dist/methodmaps/PSPlayer.csv | 77 ++ dist/methodmaps/template.csv | 9 + .../extension/api/command/Command.java | 59 +- .../extension/api/entity/player/PSPlayer.java | 932 +++++++++++++++--- .../api/translation/LanguageString.java | 7 +- .../command/general/LinkCommand.java | 2 +- .../command/general/SpeedCommand.java | 56 +- .../command/general/TrollCommand.java | 148 +-- .../general/replacement/GamemodeCommand.java | 156 +-- .../command/survival/HomeCommand.java | 137 +-- .../command/survivalcheat/FeedCommand.java | 110 ++- .../command/survivalcheat/HealCommand.java | 137 +-- .../extension/listener/ChatListener.java | 16 +- .../extension/misc/DamageDetection.java | 2 +- .../src/main/resources/translations/de.json | 7 +- .../src/main/resources/translations/en.json | 12 +- 16 files changed, 1341 insertions(+), 526 deletions(-) create mode 100644 dist/methodmaps/PSPlayer.csv create mode 100644 dist/methodmaps/template.csv diff --git a/dist/methodmaps/PSPlayer.csv b/dist/methodmaps/PSPlayer.csv new file mode 100644 index 0000000..ec16b03 --- /dev/null +++ b/dist/methodmaps/PSPlayer.csv @@ -0,0 +1,77 @@ +TYPE ,CATEGORY ,NULLVALUE,RETURN TYPE ,METHODNAME ,"METHODARGUMENTS" +STATIC ,Lists ,@NotNull ,PSPlayer @NotNull [] ,getOnline ,"" +STATIC ,Broadcast , ,void ,broadcast ,"@NotNull String message" +STATIC ,Broadcast , ,void ,broadcastTranslatable ,"@NotNull LanguageString languageString, boolean includePrefix, @NotNull Map.Entry<@NotNull String, @NotNull String> @Nullable ... placeholders" +STATIC ,Broadcast , ,void ,broadcastRaw ,"@NotNull String message" +CONSTRUC,Constructors , , , ,"" +INSTANCE,Air left , ,int ,getLeftAir ,"" +INSTANCE,Air left ,@NotNull ,PSPlayer ,setLeftAir ,"int airPoints" +INSTANCE,Attributes ,@Nullable,AttributeInstance ,getAttribute ,"@NotNull Attribute attribute" +INSTANCE,Connection , ,void ,terminate ,"" +INSTANCE,Connection , ,void ,kick ,"@NotNull String reason" +INSTANCE,Connection , ,void ,kick ,"@NotNull String reason, @NotNull PlayerKickEvent.Cause cause" +INSTANCE,Connection , ,void ,kickTranslatable ,"@NotNull LanguageString languageString, @NotNull Map.Entry<@NotNull String, @NotNull String> @Nullable... placeholders" +INSTANCE,Connection , ,void ,kickTranslatable ,"@NotNull PlayerKickEvent.Cause cause, @NotNull LanguageString languageString, @NotNull Map.Entry<@NotNull String, @NotNull String> @Nullable... placeholders" +INSTANCE,Connection , ,void ,kickRaw ,"@NotNull String reason" +INSTANCE,Connection , ,void ,kickRaw ,"@NotNull String reason, @NotNull PlayerKickEvent.Cause cause" +INSTANCE,Fall distance , ,float ,getFallDistance ,"" +INSTANCE,Fall distance ,@NotNull ,PSPlayer ,setFallDistance ,"float fallDistance" +INSTANCE,Gamemode ,@NotNull ,GameMode ,getGamemode ,"" +INSTANCE,Gamemode ,@NotNull ,PSPlayer ,setGamemode ,"@NotNull GameMode gamemode" +INSTANCE,Getters ,@NotNull ,Player ,getBukkitPlayer ,"" +INSTANCE,Getters ,@NotNull ,PSPlayer.Data ,getData ,"" +INSTANCE,Health , ,double ,getHealth ,"" +INSTANCE,Health ,@NotNull ,PSPlayer ,setHealth ,"double healthPoints" +INSTANCE,Health ,@NotNull ,PSPlayer ,heal ,"double healthPoints" +INSTANCE,Health ,@NotNull ,PSPlayer ,heal ,"double healthPoints, @NotNull EntityRegainHealthEvent.RegainReason reason" +INSTANCE,Health ,@NotNull ,PSPlayer ,damage ,"double healthPoints" +INSTANCE,Health ,@NotNull ,PSPlayer ,damage ,"double healthPoints, @NotNull Entity entity" +INSTANCE,Health ,@NotNull ,PSPlayer ,damage ,"double healthPoints, @NotNull DamageSource damageSource" +INSTANCE,Hunger , ,int ,getHunger ,"" +INSTANCE,Hunger , ,float ,getSaturation ,"" +INSTANCE,Hunger ,@NotNull ,PSPlayer ,setHunger ,"int hungerPoints" +INSTANCE,Hunger ,@NotNull ,PSPlayer ,setSaturation ,"float saturationPoints" +INSTANCE,Location ,@NotNull ,World ,getWorld ,"" +INSTANCE,Location ,@NotNull ,Location ,getLocation ,"" +INSTANCE,Location ,@Nullable,Location ,getRespawnLocation ,"" +INSTANCE,Location ,@NotNull ,PSPlayer ,teleport ,"@NotNull Location location" +INSTANCE,Location ,@NotNull ,PSPlayer ,teleport ,"@NotNull Location location, @NotNull PlayerTeleportEvent.TeleportCause cause" +INSTANCE,Location ,@NotNull ,PSPlayer ,teleport ,"@NotNull Location location, @NotNull TeleportFlag... flags" +INSTANCE,Location ,@NotNull ,PSPlayer ,teleport ,"@NotNull Location location, @NotNull PlayerTeleportEvent.TeleportCause cause, @NotNull TeleportFlag... flags" +INSTANCE,Messaging ,@NotNull ,PSPlayer ,message ,"@NotNull String message" +INSTANCE,Messaging ,@NotNull ,PSPlayer ,messageTranslatable ,"@NotNull LanguageString languageString, boolean includePrefix, @NotNull Map.Entry<@NotNull String, @NotNull String> @Nullable... placeholders" +INSTANCE,Messaging ,@NotNull ,PSPlayer ,messageRaw ,"@NotNull String message" +INSTANCE,Particles ,@NotNull ,PSPlayer ,particle ,"@NotNull Particle particle, int count" +INSTANCE,Particles ,@NotNull ,PSPlayer ,particle ,"@NotNull Particle particle, int count, @NotNull Location location" +INSTANCE,Permissions , ,boolean ,hasPermission ,"@NotNull String permission" +INSTANCE,Permissions , ,boolean ,hasPermission ,"@NotNull Permission permission" +INSTANCE,Player identification , ,boolean ,isOnline ,"" +INSTANCE,Player identification ,@NotNull ,UUID ,getUUID ,"" +INSTANCE,Player identification ,@NotNull ,String ,getUsername ,"" +INSTANCE,Player identification ,@NotNull ,String ,getIdentificationString ,"" +INSTANCE,Potion effects ,@NotNull ,PotionEffect @NotNull [],getPotions ,"" +INSTANCE,Potion effects ,@NotNull ,PSPlayer ,getPotion ,"@NotNull PotionEffectType type" +INSTANCE,Potion effects ,@NotNull ,PSPlayer ,hasPotion ,"@NotNull PotionEffectType type" +INSTANCE,Potion effects ,@NotNull ,PSPlayer ,applyPotion ,"@NotNull PotionEffect effect" +INSTANCE,Potion effects ,@NotNull ,PSPlayer ,removePotion ,"@NotNull PotionEffectType type" +INSTANCE,Scheduling ,@NotNull ,PSPlayer ,schedule ,"@NotNull Runnable task, long delay" +INSTANCE,Scheduling ,@NotNull ,PSPlayer ,schedule ,"@NotNull Runnable task, @NotNull Runnable retired, long delay" +INSTANCE,Scheduling ,@NotNull ,PSPlayer ,scheduleRepeatedly ,"@NotNull Runnable task, long delay" +INSTANCE,Screen effects ,@NotNull ,PSPlayer ,showCredits ,"" +INSTANCE,Screen effects ,@NotNull ,PSPlayer ,showDemoPopup ,"" +INSTANCE,Screen effects ,@NotNull ,PSPlayer ,showElderGuardian ,"" +INSTANCE,Screen effects ,@NotNull ,PSPlayer ,showElderGuardian ,"boolean silent" +INSTANCE,Sounds ,@NotNull ,PSPlayer ,sound ,"@NotNull Sound sound" +INSTANCE,Sounds ,@NotNull ,PSPlayer ,sound ,"@NotNull Key sound, @NotNull Sound.Source type, float volume, float pitch" +INSTANCE,Sounds ,@NotNull ,PSPlayer ,sound ,"@NotNull Key sound, @NotNull Sound.Source type" +INSTANCE,Sounds ,@NotNull ,PSPlayer ,stopSounds ,"" +INSTANCE,Sounds ,@NotNull ,PSPlayer ,stopSound ,"@NotNull Sound sound" +INSTANCE,Times ,@NotNull ,PSPlayer ,title ,"" +INSTANCE,Times ,@NotNull ,PSPlayer ,title ,"@NotNull Title title" +INSTANCE,Times ,@NotNull ,PSPlayer ,title ,"@Nullable Component title, @Nullable Component subtitle, @NotNull Title.Times times" +INSTANCE,Times ,@NotNull ,PSPlayer ,title ,"@Nullable Component title, @Nullable Component subtitle, @NotNull Duration fadeIn, @NotNull Duration stay, @NotNull Duration fadeOut" +INSTANCE,Times ,@NotNull ,PSPlayer ,title ,"@Nullable Component title, @Nullable Component subtitle, long fadeIn, long stay, long fadeOut" +INSTANCE,Times ,@NotNull ,PSPlayer ,titleRaw ,"@Nullable String title, @Nullable String subtitle, @NotNull Title.Times times" +INSTANCE,Times ,@NotNull ,PSPlayer ,titleRaw ,"@Nullable String title, @Nullable String subtitle, @NotNull Duration fadeIn, @NotNull Duration stay, @NotNull Duration fadeOut" +INSTANCE,Times ,@NotNull ,PSPlayer ,titleRaw ,"@Nullable String title, @Nullable String subtitle, long fadeIn, long stay, long fadeOut" +INSTANCE,Data ,@NotNull ,PSPlayer ,applyPlayerAttributes ,"" diff --git a/dist/methodmaps/template.csv b/dist/methodmaps/template.csv new file mode 100644 index 0000000..c3c4e85 --- /dev/null +++ b/dist/methodmaps/template.csv @@ -0,0 +1,9 @@ +TYPE ,CATEGORY ,NULLVALUE,RETURN TYPE ,METHODNAME ,"METHODARGUMENTS" +STATIC ,Getters ,@NotNull ,Class @Nullable [] ,getSomeClass ,"@NotNull String name" +CONSTRUC,Constructors , , , ,"" +INSTANCE,Termination , ,void ,terminate ,"" +INSTANCE,Termination , ,void ,terminate ,"@NotNull Cause cause" +INSTANCE,Termination , ,void ,terminate ,"@NotNull String reason" +INSTANCE,Termination , ,void ,terminate ,"@NotNull String reason, @NotNull Cause cause" +INSTANCE,Checks , ,boolean ,exists ,"@NotNull Object thing" +INSTANCE,Checks , ,boolean ,existsWithCondition ,"@NotNull Object thing, @NotNull Condition ... conditions" diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/api/command/Command.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/api/command/Command.java index c39820f..a9f62e2 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/api/command/Command.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/api/command/Command.java @@ -328,6 +328,7 @@ public abstract class Command implements CommandExecutor { true, entry("player", arguments[index]) )); + throw new IllegalArgumentException("The specified target player '" + arguments[index] + "' isn't online or is invalid"); } else player = PSPlayerFactory.get(bukkitPlayer); @@ -338,6 +339,42 @@ public abstract class Command implements CommandExecutor { } } + /** + * Determines the target player. + * + * @param player command sender + * @param arguments array of arguments + * @param index index of the player name to check at + * @return target player and if the supplied command sender was used + * @throws IndexOutOfBoundsException if the size of {@code arguments} is smaller than the specified {@code index} + * @throws IllegalCallerException if no target was specified in {@code arguments} and the sender is the server console + * @throws IllegalArgumentException if the specified target in {@code arguments} is invalid or does not exist + * @since v1-release0 + */ + public static @NotNull Map.Entry<@NotNull PSPlayer, @NotNull Boolean> determineTarget(@NotNull PSPlayer player, @NotNull String @NotNull [] arguments, int index) throws IndexOutOfBoundsException, IllegalCallerException, IllegalArgumentException { + if (arguments.length == index) { + return entry(player, true); + } else if (arguments.length > index) { + Player bukkitPlayer = Bukkit.getPlayer(arguments[index]); + PSPlayer target; + + if (bukkitPlayer == null) { + player.messageTranslatable( + LanguageString.ERROR_PLAYER_NOT_FOUND, + true, + entry("player", arguments[index]) + ); + + throw new IllegalArgumentException("The specified target player '" + arguments[index] + "' isn't online or is invalid"); + } else + target = PSPlayerFactory.get(bukkitPlayer); + + return entry(target, target.getUsername().equals(player.getUsername())); + } else { + throw new IndexOutOfBoundsException("Size of 'arguments' is smaller than the specified 'index'"); + } + } + // -----> Inner classes /** * Represents by whom a command can be used. @@ -417,7 +454,7 @@ public abstract class Command implements CommandExecutor { @NotNull String description, @NotNull String syntax, @NotNull String mode, - @Range(from = 0, to = 2) int @Nullable [] executionOrder, + @NotNull String @Nullable [] executionOrder, @NotNull Command.ExecutionTarget executionTarget ) { /** @@ -426,28 +463,28 @@ public abstract class Command implements CommandExecutor { */ public Information { if (executionOrder == null) - executionOrder = new int[]{ 0, 1, 2 }; + executionOrder = new String[]{ "all", "console", "player" }; // Verify 'executionOrder' // -> Amount of items if (executionOrder.length != 3) throw new IllegalStateException("'executionOrder' does not contain exactly three items"); - // -> Bounds + // -> Options if ( - (executionOrder[0] < 0 || executionOrder[0] > 2) - || (executionOrder[1] < 0 || executionOrder[1] > 2) - || (executionOrder[2] < 0 || executionOrder[2] > 2) + (!executionOrder[0].equals("all") && !executionOrder[0].equals("console") && !executionOrder[0].equals("player")) + || (!executionOrder[1].equals("all") && !executionOrder[1].equals("console") && !executionOrder[1].equals("player")) + || (!executionOrder[2].equals("all") && !executionOrder[2].equals("console") && !executionOrder[2].equals("player")) ) - throw new IllegalStateException("Some item in 'executionOrder' is either smaller than '0' or bigger than '2'"); + throw new IllegalStateException("Some item in 'executionOrder' is neither \"all\", \"console\" nor \"player\""); // -> Duplicate values if ( - executionOrder[0] == executionOrder[1] - || executionOrder[0] == executionOrder[2] - || executionOrder[1] == executionOrder[2] + executionOrder[0].equals(executionOrder[1]) + || executionOrder[0].equals(executionOrder[2]) + || executionOrder[1].equals(executionOrder[2]) ) - throw new IllegalStateException("Two or more items in 'executionOrder' have the same value"); + throw new IllegalStateException("Duplicate values found in 'executionOrder'"); } } } diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/api/entity/player/PSPlayer.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/api/entity/player/PSPlayer.java index 4c1f8ec..36dd7c3 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/api/entity/player/PSPlayer.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/api/entity/player/PSPlayer.java @@ -28,25 +28,35 @@ import de.jeremystartm.pickshadow.extension.api.type.PlayerAttribute; import de.jeremystartm.pickshadow.extension.api.type.PlayerDamageState; import de.staropensource.engine.base.logging.Logger; import fr.mrmicky.fastboard.adventure.FastBoard; +import io.netty.util.NettyRuntime; +import io.papermc.paper.entity.TeleportFlag; import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.sound.Sound; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.title.Title; +import net.minecraft.network.DisconnectionDetails; import net.minecraft.server.MinecraftServer; -import org.bukkit.Bukkit; -import org.bukkit.GameMode; -import org.bukkit.Location; -import org.bukkit.World; +import org.bukkit.*; +import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeInstance; import org.bukkit.damage.DamageSource; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; +import org.bukkit.event.entity.EntityRegainHealthEvent; import org.bukkit.event.player.PlayerKickEvent; +import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.permissions.Permission; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.time.Duration; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.*; @@ -59,7 +69,9 @@ import static java.util.Map.entry; * * @since v1-release0 */ -@Getter +// This class has a method map. +// To get an overview of all methods, open +// the '/dist/methodsmaps/PSPlayer.csv' file @SuppressWarnings({ "UnusedReturnValue", "unused" }) public final class PSPlayer { /** @@ -73,6 +85,7 @@ public final class PSPlayer { * * @since v1-release0 */ + @Getter private final @NotNull PSPlayer.Data data; /** @@ -80,37 +93,18 @@ public final class PSPlayer { * associated to this player. * * @since v1-release0 - * -- GETTER -- - * Returns the {@link Player} instance - * associated to this player. - * - * @since v1-release0 */ - @ApiStatus.Obsolete private final @NotNull Player bukkitPlayer; - /** - * Creates and initializes an - * instance of this class. - * - * @param player Bukkit {@link Player} - * @since v1-release0 - */ - PSPlayer(@NotNull Player player) { - // Set final variables - bukkitPlayer = player; - data = new Data(this); - } - - // -----> Static + // -----> List /** * Returns an array of all online players. * * @return online players array * @since v1-release0 */ - public static @NotNull PSPlayer[] getOnline() { + public static @NotNull PSPlayer @NotNull [] getOnline() { List players = new ArrayList<>(); for (Player player : Bukkit.getOnlinePlayers()) @@ -121,6 +115,8 @@ public final class PSPlayer { return players.toArray(new PSPlayer[0]); } + + // -----> Broadcast /** * Broadcasts the specified message * to all online players. @@ -173,69 +169,55 @@ public final class PSPlayer { } - // -----> Information + // -----> Constructors /** - * Returns if this player is online. - *

- * This method will pretty much - * always return {@code true}. + * Creates and initializes an + * instance of this class. * - * @return online? + * @param player Bukkit {@link Player} * @since v1-release0 */ - public boolean isOnline() { - return bukkitPlayer.isOnline(); + PSPlayer(@NotNull Player player) { + // Set final variables + bukkitPlayer = player; + data = new Data(this); + } + + + // -----> Air left + /** + * Returns the amount of air this player has left. + * + * @return air points + * @since v1-release0 + */ + public int getAirLeft() { + return bukkitPlayer.getRemainingAir(); } /** - * Returns this player's {@link UUID}. + * Sets the amount of air this player has left. * - * @return player {@link UUID} + * @param airPoints new air points + * @return this instance * @since v1-release0 */ - public @NotNull UUID getUUID() { - return bukkitPlayer.getUniqueId(); + public @NotNull PSPlayer setAirLeft(int airPoints) { + bukkitPlayer.setRemainingAir(airPoints); + return this; } - /** - * Returns this player's username. - * - * @return username - * @since v1-release0 - */ - public @NotNull String getUsername() { - return bukkitPlayer.getName(); - } + // -----> Attributes /** - * Returns the full player identification - * for use in log messages and other strings. + * Returns the specified attribute. * - * @return human-friendly player identification string + * @param attribute attribute to return + * @return matching {@link AttributeInstance} or {@code null} if not applicable * @since v1-release0 */ - public @NotNull String getIdentificationString() { - return getUsername() + " [" + getUUID() + "]"; - } - - /** - * Returns the position of this player. - * - * @return position - * @since v1-release0 - */ - public @NotNull Location getPosition() { - return bukkitPlayer.getLocation(); - } - - /** - * Returns the world this player is in. - * - * @return world - * @since v1-release0 - */ - public @NotNull World getWorld() { - return bukkitPlayer.getWorld(); + public @Nullable AttributeInstance getAttribute(@NotNull Attribute attribute) { + return bukkitPlayer.getAttribute(attribute); } @@ -243,13 +225,31 @@ public final class PSPlayer { /** * Terminates the connection to the player. *

- * This will instantaneously remove the player - * from the game without informing them. As if - * their internet connection died. + * This will instantaneously remove this player + * from the game without really informing them. + * As if the server errored out or the + * connection died unexpectedly. * * @since v1-release0 */ public void terminate() { + Objects.requireNonNull(MinecraftServer.getServer().getPlayerList().getPlayer(bukkitPlayer.getUniqueId())).connection.connection.disconnect(net.minecraft.network.chat.Component.literal("Connection was terminated by PSSE")); + } + + /** + * Puts the connection into a limbo state. + *

+ * This command effectively declares this + * player as disconnected without + * terminating the connection. + *

+ * The effects of this are unknown. Data + * loss may occur. Not recommended. + * + * @since v1-release0 + */ + @ApiStatus.Experimental + public void connectionLimbo() { Objects.requireNonNull(MinecraftServer.getServer().getPlayerList().getPlayer(bukkitPlayer.getUniqueId())).disconnect(); } @@ -340,6 +340,294 @@ public final class PSPlayer { } + // -----> Fall Distance + /** + * Returns the amount of height accumulated during a fall. + * + * @return fall distance + * @since v1-release0 + */ + public float getFallDistance() { + return bukkitPlayer.getFallDistance(); + } + + /** + * Sets the amount of height accumulated during a fall. + * + * @param fallDistance new fall distance + * @return this instance + * @since v1-release0 + */ + public @NotNull PSPlayer setFallDistance(float fallDistance) { + bukkitPlayer.setFallDistance(fallDistance); + return this; + } + + + // -----> Gamemode + /** + * Returns this player's gamemode. + * + * @return gamemode + * @since v1-release0 + */ + public @NotNull GameMode getGamemode() { + return bukkitPlayer.getGameMode(); + } + + /** + * Sets this player's gamemode. + * + * @param gamemode new gamemode + * @return this instance + * @since v1-release0 + */ + public @NotNull PSPlayer setGamemode(@NotNull GameMode gamemode) { + bukkitPlayer.setGameMode(gamemode); + + // Reset speed if now in spectator mode + if (gamemode == GameMode.SPECTATOR) { + bukkitPlayer.setFlySpeed(0.1f); + bukkitPlayer.setWalkSpeed(0.2f); + } + + return this; + } + + + // -----> Getters + /** + * Returns the associated Bukkit {@link Player}. + * + * @return associated Bukkit {@link Player} + * @deprecated Use the methods provided by {@link PSPlayer} + * @since v1-release0 + */ + @SuppressWarnings("DeprecatedIsStillUsed") + @Deprecated + public @NotNull Player getBukkitPlayer() { + return bukkitPlayer; + } + + + // -----> Health + /** + * Returns the amount of health points this player has. + * + * @return health points + * @since v1-release0 + */ + public double getHealth() { + return bukkitPlayer.getHealth(); + } + + /** + * Sets the amount of health points this player has. + * + * @param healthPoints new health points + * @return this instance + * @since v1-release0 + */ + public @NotNull PSPlayer setHealth(double healthPoints) { + bukkitPlayer.setHealth(healthPoints); + return this; + } + + /** + * Heals this player. + * + * @param healthPoints amount of health points to heal + * @return this instance + * @since v1-release0 + */ + public @NotNull PSPlayer heal(double healthPoints) { + bukkitPlayer.heal(healthPoints); + return this; + } + + /** + * Heals this player. + * + * @param healthPoints amount of health points to heal + * @param reason heal reason + * @return this instance + * @since v1-release0 + */ + public @NotNull PSPlayer heal(double healthPoints, @NotNull EntityRegainHealthEvent.RegainReason reason) { + bukkitPlayer.heal(healthPoints, reason); + return this; + } + + /** + * Damages this player. + * + * @param healthPoints amount of damage to deal in health points + * @return this instance + * @since v1-release0 + */ + public @NotNull PSPlayer damage(double healthPoints) { + bukkitPlayer.damage(healthPoints); + return this; + } + + /** + * Damages this player. + * + * @param healthPoints amount of damage to deal in health points + * @param entity entity which dealt the damage + * @return this instance + * @since v1-release0 + */ + public @NotNull PSPlayer damage(double healthPoints, @NotNull Entity entity) { + bukkitPlayer.damage(healthPoints, entity); + return this; + } + + /** + * Damages this player. + * + * @param healthPoints amount of damage to deal in health points + * @param damageSource information about what the damage caused + * @return this instance + * @since v1-release0 + */ + @SuppressWarnings("UnstableApiUsage") + public @NotNull PSPlayer damage(double healthPoints, @NotNull DamageSource damageSource) { + bukkitPlayer.damage(healthPoints, damageSource); + return this; + } + + + // -----> Hunger + /** + * Returns the amount of hunger points this player has. + * + * @return hunger points + * @since v1-release0 + */ + public int getHunger() { + return bukkitPlayer.getFoodLevel(); + } + + /** + * Returns the amount of saturation this player has. + * + * @return saturation points + * @since v1-release0 + */ + public float getSaturation() { + return bukkitPlayer.getSaturation(); + } + + /** + * Sets the amount of hunger this player has. + * + * @param hungerPoints new hunger points + * @return this instance + * @since v1-release0 + */ + public @NotNull PSPlayer setHunger(int hungerPoints) { + bukkitPlayer.setFoodLevel(hungerPoints); + return this; + } + + /** + * Sets the amount of saturation this player has. + * + * @param saturationPoints new saturation points + * @return this instance + * @since v1-release0 + */ + public @NotNull PSPlayer setSaturation(float saturationPoints) { + bukkitPlayer.setSaturation(saturationPoints); + return this; + } + + + // -----> Location + /** + * Returns the world this player is in. + * + * @return world + * @since v1-release0 + */ + public @NotNull World getWorld() { + return bukkitPlayer.getWorld(); + } + + /** + * Returns the location of this player. + * + * @return location + * @since v1-release0 + */ + public @NotNull Location getLocation() { + return bukkitPlayer.getLocation(); + } + + /** + * Returns the respawn location of this player. + * + * @return respawn location or {@code null} if invalid + * @since v1-release0 + */ + public @Nullable Location getRespawnLocation() { + return bukkitPlayer.getRespawnLocation(); + } + + /** + * Teleports this player. + * + * @param location location to teleport to + * @return this instance + * @since v1-release0 + */ + public @NotNull PSPlayer teleport(@NotNull Location location) { + bukkitPlayer.teleport(location); + return this; + } + + /** + * Teleports this player. + * + * @param location location to teleport to + * @param cause cause of the teleportation + * @return this instance + * @since v1-release0 + */ + public @NotNull PSPlayer teleport(@NotNull Location location, @NotNull PlayerTeleportEvent.TeleportCause cause) { + bukkitPlayer.teleport(location, cause); + return this; + } + + /** + * Teleports this player. + * + * @param location location to teleport to + * @param flags teleportation flags + * @return this instance + * @since v1-release0 + */ + public @NotNull PSPlayer teleport(@NotNull Location location, @NotNull TeleportFlag... flags) { + bukkitPlayer.teleport(location, flags); + return this; + } + + /** + * Teleports this player. + * + * @param location location to teleport to + * @param cause cause of the teleportation + * @param flags teleportation flags + * @return this instance + * @since v1-release0 + */ + public @NotNull PSPlayer teleport(@NotNull Location location, @NotNull PlayerTeleportEvent.TeleportCause cause, @NotNull TeleportFlag... flags) { + bukkitPlayer.teleport(location, cause, flags); + return this; + } + + // -----> Messaging /** * Messages this player. @@ -391,68 +679,35 @@ public final class PSPlayer { } - // -----> Scheduling + // -----> Particles /** - * Schedules an action. + * Spawns the specified particle. * - * @param task {@link Runnable} to invoke after the set delay - * @param delay delay in ticks; values lower than {@code 1} will be treated as {@code 0} + * @param particle particle to spawn + * @param count number of times to spawn the specified particle + * @return this instance * @since v1-release0 */ - public void schedule(@NotNull Runnable task, long delay) { - if (delay < 1L) - delay = 1L; - - bukkitPlayer.getScheduler().execute(Extension.getInstance(), task, null, delay); + public @NotNull PSPlayer particle(@NotNull Particle particle, int count) { + bukkitPlayer.spawnParticle(particle, getLocation(), count); + return this; } /** - * Schedules an action. + * Spawns the specified particle. * - * @param task {@link Runnable} to invoke after the set delay - * @param retired {@link Runnable} to invoke if the player disconnects during the delay - * @param delay delay in ticks; values lower than {@code 1} will be treated as {@code 0} + * @param particle particle to spawn + * @param count number of times to spawn the specified particle + * @return this instance * @since v1-release0 */ - public void schedule(@NotNull Runnable task, @NotNull Runnable retired, long delay) { - if (delay < 1L) - delay = 1L; - - bukkitPlayer.getScheduler().execute(Extension.getInstance(), task, retired, delay); - } - - /** - * Schedules an action to execute repeatedly - * until this player disconnects. - * - * @param task {@link Runnable} to invoke after the set delay - * @param delay delay in ticks; values lower than {@code 1} will be treated as {@code 0} - * @since v1-release0 - */ - public void scheduleRepeatedly(@NotNull Runnable task, long delay) { - if (delay < 1L) - delay = 1L; - - long finalDelay = delay; - bukkitPlayer.getScheduler().execute(Extension.getInstance(), () -> { - task.run(); - - scheduleRepeatedly(task, finalDelay); - }, null, delay); + public @NotNull PSPlayer particle(@NotNull Particle particle, int count, @NotNull Location location) { + bukkitPlayer.spawnParticle(particle, location, count); + return this; } - // -----> Miscellaneous - /** - * Checks whether the specified permission is set. - * - * @param permission permission to check - * @return set? - * @since v1-release0 - */ - public boolean hasPermission(@NotNull Permission permission) { - return bukkitPlayer.hasPermission(permission); - } + // -----> Permissions /** * Checks whether the specified permission is set. * @@ -465,85 +720,434 @@ public final class PSPlayer { } /** - * Returns the amount of height accumulated during a fall. + * Checks whether the specified permission is set. * - * @return fall distance + * @param permission permission to check + * @return set? * @since v1-release0 */ - public float getFallDistance() { - return bukkitPlayer.getFallDistance(); + public boolean hasPermission(@NotNull Permission permission) { + return bukkitPlayer.hasPermission(permission); + } + + + // -----> Player identification + /** + * Returns if this player is online. + *

+ * This method will pretty much + * always return {@code true}. + * + * @return online? + * @since v1-release0 + */ + public boolean isOnline() { + return bukkitPlayer.isOnline(); } /** - * Sets the amount of height accumulated during a fall. + * Returns this player's {@link UUID}. * - * @param fallDistance new fall distance - * @return this instance + * @return player {@link UUID} * @since v1-release0 */ - public @NotNull PSPlayer setFallDistance(float fallDistance) { - bukkitPlayer.setFallDistance(fallDistance); + public @NotNull UUID getUUID() { + return bukkitPlayer.getUniqueId(); + } + + /** + * Returns this player's username. + * + * @return username + * @since v1-release0 + */ + public @NotNull String getUsername() { + return bukkitPlayer.getName(); + } + + /** + * Returns the full player identification + * for use in log messages and other strings. + * + * @return human-friendly player identification string + * @since v1-release0 + */ + public @NotNull String getIdentificationString() { + return getUsername() + " [" + getUUID() + "]"; + } + + + // -----> Potion effects + /** + * Returns an array of potions this player has applied. + * + * @return array of applied potions + * @since v1-release0 + */ + public @NotNull PotionEffect @NotNull [] getPotions() { + return bukkitPlayer.getActivePotionEffects().toArray(new PotionEffect[0]); + } + + /** + * Returns an array of potions this player has applied. + * + * @param type potion type to get + * @return {@link PotionEffect} instance or {@code null} if inactive + * @since v1-release0 + */ + public @NotNull PSPlayer getPotion(@NotNull PotionEffectType type) { + bukkitPlayer.getPotionEffect(type); return this; } /** - * Returns this player's gamemode. + * Returns if the specified potion is applied. * - * @return gamemode - * @since v1-release0 - */ - public @NotNull GameMode getGamemode() { - return bukkitPlayer.getGameMode(); - } - - /** - * Sets this player's gamemode. - * - * @param gamemode new gamemode + * @param type potion type to check * @return this instance * @since v1-release0 */ - public @NotNull PSPlayer setGamemode(@NotNull GameMode gamemode) { - bukkitPlayer.setGameMode(gamemode); + public @NotNull PSPlayer hasPotion(@NotNull PotionEffectType type) { + bukkitPlayer.hasPotionEffect(type); return this; } /** - * Damages this player. + * Applies the specified potion effect to this player. * - * @param healthPoints amount of damage to deal in health points + * @param effect potion to apply * @return this instance * @since v1-release0 */ - public @NotNull PSPlayer damage(double healthPoints) { - bukkitPlayer.damage(healthPoints); + public @NotNull PSPlayer applyPotion(@NotNull PotionEffect effect) { + bukkitPlayer.addPotionEffect(effect); return this; } /** - * Damages this player. + * Removes the specified potion effect on this player. * - * @param healthPoints amount of damage to deal in health points - * @param entity entity which dealt the damage + * @param type potion type to remove * @return this instance * @since v1-release0 */ - public @NotNull PSPlayer damage(double healthPoints, @NotNull Entity entity) { - bukkitPlayer.damage(healthPoints, entity); + public @NotNull PSPlayer removePotion(@NotNull PotionEffectType type) { + bukkitPlayer.removePotionEffect(type); + return this; + } + + + // -----> Scheduling + /** + * Schedules an action. + * + * @param task {@link Runnable} to invoke after the set delay + * @param delay delay in ticks; values lower than {@code 1} will be treated as {@code 0} + * @return this instance + * @since v1-release0 + */ + public @NotNull PSPlayer schedule(@NotNull Runnable task, long delay) { + if (delay < 1L) + delay = 1L; + + bukkitPlayer.getScheduler().execute(Extension.getInstance(), task, null, delay); return this; } /** - * Damages this player. + * Schedules an action. * - * @param healthPoints amount of damage to deal in health points - * @param damageSource information about what the damage caused + * @param task {@link Runnable} to invoke after the set delay + * @param retired {@link Runnable} to invoke if the player disconnects during the delay + * @param delay delay in ticks; values lower than {@code 1} will be treated as {@code 0} * @return this instance * @since v1-release0 */ - @SuppressWarnings("UnstableApiUsage") - public @NotNull PSPlayer damage(double healthPoints, @NotNull DamageSource damageSource) { - bukkitPlayer.damage(healthPoints, damageSource); + public @NotNull PSPlayer schedule(@NotNull Runnable task, @NotNull Runnable retired, long delay) { + if (delay < 1L) + delay = 1L; + + bukkitPlayer.getScheduler().execute(Extension.getInstance(), task, retired, delay); + return this; + } + + /** + * Schedules an action to execute repeatedly + * until this player disconnects. + * + * @param task {@link Runnable} to invoke after the set delay + * @param delay delay in ticks; values lower than {@code 1} will be treated as {@code 0} + * @return this instance + * @since v1-release0 + */ + public @NotNull PSPlayer scheduleRepeatedly(@NotNull Runnable task, long delay) { + if (delay < 1L) + delay = 1L; + + long finalDelay = delay; + bukkitPlayer.getScheduler().execute(Extension.getInstance(), () -> { + task.run(); + + scheduleRepeatedly(task, finalDelay); + }, null, delay); + + return this; + } + + + // -----> Screen effects + /** + * Shows this player the the credits sequence. + * + * @since v1-release0 + */ + public @NotNull PSPlayer showCredits() { + bukkitPlayer.showWinScreen(); + return this; + } + + /** + * Shows this player the demo popup. + * + * @see screenshot of the demo popup + * @since v1-release0 + */ + public @NotNull PSPlayer showDemoPopup() { + bukkitPlayer.showDemoScreen(); + return this; + } + + /** + * Shows this player the elder guardian. + * + * @since v1-release0 + */ + public @NotNull PSPlayer showElderGuardian() { + bukkitPlayer.showElderGuardian(); + return this; + } + + /** + * Shows this player the elder guardian. + * + * @since v1-release0 + */ + public @NotNull PSPlayer showElderGuardian(boolean silent) { + bukkitPlayer.showElderGuardian(silent); + return this; + } + + + // -----> Sounds + /** + * Plays the specified sound effect. + * + * @param sound sound to play + * @return this instance + * @since v1-release0 + */ + public @NotNull PSPlayer sound(@NotNull Sound sound) { + bukkitPlayer.playSound(sound); + return this; + } + + /** + * Plays the specified sound effect. + * + * @param sound sound to play + * @param type type of sound + * @param volume sound volume + * @param pitch sound pitch + * @return this instance + * @since v1-release0 + */ + public @NotNull PSPlayer sound(@NotNull Key sound, @NotNull Sound.Source type, float volume, float pitch) { + bukkitPlayer.playSound(Sound.sound(sound, type, volume, pitch)); + return this; + } + + /** + * Plays the specified sound effect. + * + * @param sound sound to play + * @param type type of sound + * @return this instance + * @since v1-release0 + */ + public @NotNull PSPlayer sound(@NotNull Key sound, @NotNull Sound.Source type) { + bukkitPlayer.playSound(Sound.sound(sound, type, 1f, 1f)); + return this; + } + + /** + * Stops all currently playing sounds. + * + * @return this instance + * @since v1-release0 + */ + public @NotNull PSPlayer stopSounds() { + bukkitPlayer.stopAllSounds(); + return this; + } + + /** + * Stops the specified sound. + * + * @return this instance + * @since v1-release0 + */ + public @NotNull PSPlayer stopSound(@NotNull Sound sound) { + bukkitPlayer.stopSound(sound); + return this; + } + + + // -----> Titles + /** + * Resets the displayed title. + * + * @since v1-release0 + */ + public @NotNull PSPlayer title() { + bukkitPlayer.resetTitle(); + return this; + } + + /** + * Displays the specified title. + * + * @param title {@link Title} + * @since v1-release0 + */ + public @NotNull PSPlayer title(@NotNull Title title) { + bukkitPlayer.showTitle(title); + return this; + } + + /** + * Displays the specified title. + * + * @param title title + * @param subtitle subtitle + * @param times timing details + * @since v1-release0 + */ + public @NotNull PSPlayer title(@Nullable Component title, @Nullable Component subtitle, @NotNull Title.Times times) { + bukkitPlayer.showTitle(Title.title( + title == null ? Component.empty() : title, + subtitle == null ? Component.empty() : subtitle, + times + )); + return this; + } + + /** + * Displays the specified title. + * + * @param title title + * @param subtitle subtitle + * @param fadeIn time the fade in animation shall take + * @param stay how long the title shall be shown + * @param fadeOut time the fade out animation shall take + * @since v1-release0 + */ + public @NotNull PSPlayer title(@Nullable Component title, @Nullable Component subtitle, @NotNull Duration fadeIn, @NotNull Duration stay, @NotNull Duration fadeOut) { + bukkitPlayer.showTitle(Title.title( + title == null ? Component.empty() : title, + subtitle == null ? Component.empty() : subtitle, + Title.Times.times( + fadeIn, + stay, + fadeOut + ) + )); + return this; + } + + /** + * Displays the specified title. + * + * @param title title + * @param subtitle subtitle + * @param fadeIn time the fade in animation shall take + * @param stay how long the title shall be shown + * @param fadeOut time the fade out animation shall take + * @since v1-release0 + */ + public @NotNull PSPlayer title(@Nullable Component title, @Nullable Component subtitle, long fadeIn, long stay, long fadeOut) { + bukkitPlayer.showTitle(Title.title( + title == null ? Component.empty() : title, + subtitle == null ? Component.empty() : subtitle, + Title.Times.times( + Duration.ofMillis(fadeIn), + Duration.ofMillis(stay), + Duration.ofMillis(fadeOut) + ) + )); + return this; + } + + /** + * Displays the specified title. + * + * @param title title + * @param subtitle subtitle + * @param times timing details + * @since v1-release0 + */ + public @NotNull PSPlayer titleRaw(@Nullable String title, @Nullable String subtitle, @NotNull Title.Times times) { + bukkitPlayer.showTitle(Title.title( + title == null ? Component.empty() : Component.text(title), + subtitle == null ? Component.empty() : Component.text(subtitle), + times + )); + return this; + } + + /** + * Displays the specified title. + * + * @param title title + * @param subtitle subtitle + * @param fadeIn time the fade in animation shall take + * @param stay how long the title shall be shown + * @param fadeOut time the fade out animation shall take + * @since v1-release0 + */ + public @NotNull PSPlayer titleRaw(@Nullable String title, @Nullable String subtitle, @NotNull Duration fadeIn, @NotNull Duration stay, @NotNull Duration fadeOut) { + bukkitPlayer.showTitle(Title.title( + title == null ? Component.empty() : Component.text(title), + subtitle == null ? Component.empty() : Component.text(subtitle), + Title.Times.times( + fadeIn, + stay, + fadeOut + ) + )); + return this; + } + + /** + * Displays the specified title. + * + * @param title title + * @param subtitle subtitle + * @param fadeIn time the fade in animation shall take + * @param stay how long the title shall be shown + * @param fadeOut time the fade out animation shall take + * @since v1-release0 + */ + public @NotNull PSPlayer titleRaw(@Nullable String title, @Nullable String subtitle, long fadeIn, long stay, long fadeOut) { + bukkitPlayer.showTitle( + Title.title( + title == null ? Component.empty() : Component.text(title), + subtitle == null ? Component.empty() : Component.text(subtitle), + Title.Times.times( + Duration.ofMillis(fadeIn), + Duration.ofMillis(stay), + Duration.ofMillis(fadeOut) + ) + )); return this; } @@ -559,6 +1163,10 @@ public final class PSPlayer { for (PlayerAttribute attribute : PlayerAttribute.values()) switch (attribute) { case WALKING_SPEED, FLY_SPEED -> { + // Don't affect spectator mode + if (getGamemode() == GameMode.SPECTATOR) + continue; + // Calculate float speed = (float) data.getPlayerAttribute(attribute) + (float) data.getPlayerAttributeOverride(attribute); diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/api/translation/LanguageString.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/api/translation/LanguageString.java index 32c2d67..109d6cc 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/api/translation/LanguageString.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/api/translation/LanguageString.java @@ -78,10 +78,10 @@ public enum LanguageString { // Command group 'links' LINKS_WEBSITE, - LINKS_FORUM, - LINKS_DISCORD, - LINKS_TEAMSPEAK, + LINKS_MESSAGEBOARD, LINKS_MUMBLE, + LINKS_TEAMSPEAK, + LINKS_DISCORD, // Command /clearchat CLEARCHAT_GENERIC, @@ -92,6 +92,7 @@ public enum LanguageString { // Command /home HOME, + HOME_OTHER, HOME_NORESPAWN, HOME_NORESPAWN_OTHER, diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/LinkCommand.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/LinkCommand.java index 0338a29..3d2f6d0 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/LinkCommand.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/LinkCommand.java @@ -73,7 +73,7 @@ public final class LinkCommand extends Command { switch (alias) { case "website" -> sender.sendRichMessage(TranslationManager.get(LanguageString.LINKS_WEBSITE, sender, true)); - case "forum", "messageboard", "mb" -> sender.sendRichMessage(TranslationManager.get(LanguageString.LINKS_FORUM, sender, true)); + case "forum", "messageboard", "mb" -> sender.sendRichMessage(TranslationManager.get(LanguageString.LINKS_MESSAGEBOARD, sender, true)); case "discord", "dc" -> sender.sendRichMessage(TranslationManager.get(LanguageString.LINKS_DISCORD, sender, true)); case "teamspeak", "ts" -> sender.sendRichMessage(TranslationManager.get(LanguageString.LINKS_TEAMSPEAK, sender, true)); case "mumble" -> sender.sendRichMessage(TranslationManager.get(LanguageString.LINKS_MUMBLE, sender, true)); diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/SpeedCommand.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/SpeedCommand.java index dbe5d49..024cd61 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/SpeedCommand.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/SpeedCommand.java @@ -23,16 +23,15 @@ import de.jeremystartm.pickshadow.extension.api.command.Command; import de.jeremystartm.pickshadow.extension.api.command.TabCompletion; import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion; import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayer; -import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayerFactory; import de.jeremystartm.pickshadow.extension.api.translation.LanguageString; import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager; import de.jeremystartm.pickshadow.extension.api.type.PlayerAttribute; import lombok.Getter; -import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; +import java.util.Map; + import static java.util.Map.entry; /** @@ -92,7 +91,7 @@ public final class SpeedCommand extends Command { /** {@inheritDoc} */ @Override - protected void invokeAll(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] arguments) { + protected void invokeAll(@NotNull CommandSender sender, @NotNull String alias, @NotNull String @NotNull [] arguments) { if (checkPermission(sender, "pickshadow.command.speed")) return; // Check length of 'arguments' @@ -104,8 +103,8 @@ public final class SpeedCommand extends Command { return; } - boolean onSelf; PSPlayer target; + boolean onSelf; float speed; boolean mode; @@ -149,46 +148,13 @@ public final class SpeedCommand extends Command { if (speed < 0f) speed = 0f; - // Get player/'target' - switch (arguments.length) { - case 2 -> { - onSelf = true; - - // Check if command sender is a player - if (sender instanceof Player senderPlayer) - target = PSPlayerFactory.get(senderPlayer); - else { - sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_NOT_A_PLAYER, sender, true)); - return; - } - } - case 3 -> { - Player bukkitPlayer = Bukkit.getPlayer(arguments[2]); - - // Check if 'bukkitPlayer' is null - if (bukkitPlayer == null) { - sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_PLAYER_NOT_FOUND, - sender, - true, - entry("player", arguments[2]) - )); - return; - } - - // Set 'onSelf' - try { - onSelf = bukkitPlayer.getName().equals(sender.getName()); - } catch (NullPointerException exception) { - onSelf = false; - } - - // Set 'target' - target = PSPlayerFactory.get(bukkitPlayer); - } - default -> { - sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_TOO_MANY_ARGUMENTS, sender, true)); - return; - } + // Get 'target' and 'onSelf' + try { + Map.Entry<@NotNull PSPlayer, @NotNull Boolean> targetEntry = determineTarget(sender, arguments, 2); + target = targetEntry.getKey(); + onSelf = targetEntry.getValue(); + } catch (Exception exception) { + return; } // Set speed diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/TrollCommand.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/TrollCommand.java index 5b12515..a988a49 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/TrollCommand.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/TrollCommand.java @@ -19,23 +19,20 @@ package de.jeremystartm.pickshadow.extension.command.general; -import de.jeremystartm.pickshadow.extension.Extension; import de.jeremystartm.pickshadow.extension.api.command.Command; import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion; import de.jeremystartm.pickshadow.extension.api.command.TabCompletion; +import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayer; +import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayerFactory; import de.jeremystartm.pickshadow.extension.api.translation.LanguageString; import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager; import lombok.Getter; import net.kyori.adventure.key.Key; import net.kyori.adventure.sound.Sound; -import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.MiniMessage; -import net.kyori.adventure.title.Title; -import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Particle; import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import java.time.Duration; @@ -90,7 +87,7 @@ public final class TrollCommand extends Command { /** {@inheritDoc} */ @Override - protected void invokeAll(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] arguments) { + protected void invokeAll(@NotNull CommandSender sender, @NotNull String alias, @NotNull String @NotNull [] arguments) { if (checkPermission(sender, "pickshadow.command.troll")) return; @@ -99,87 +96,124 @@ public final class TrollCommand extends Command { return; } - Player target = Bukkit.getPlayer(arguments[0]); - if (target == null) { - sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_PLAYER_NOT_FOUND, sender, true, entry("player", arguments[0]))); + // Determine target + PSPlayer target; + try { + target = PSPlayerFactory.get(arguments[0]); + } catch (NullPointerException exception) { + sender.sendRichMessage(TranslationManager.get( + LanguageString.ERROR_PLAYER_NOT_FOUND, + sender, + true, + entry("player", arguments[0]) + )); return; } switch (arguments[1]) { case "crash" -> { - sender.sendRichMessage(TranslationManager.get(LanguageString.TROLL_CRASH, sender, true, entry("target", target.getName()))); - for (int i = 0; i < 10000; i++) - target.spawnParticle(Particle.EXPLOSION, target.getLocation(), 100000); + sender.sendRichMessage(TranslationManager.get( + LanguageString.TROLL_CRASH, + sender, + true, + entry("target", target.getUsername()) + )); + //for (int i = 0; i < 10000; i++) + // target.particle(Particle.EXPLOSION, 1000000, target.getLocation()); + target.terminate(); } case "credits" -> { - sender.sendRichMessage(TranslationManager.get(LanguageString.TROLL_CREDITS, sender, true, entry("target", target.getName()))); - target.showWinScreen(); + sender.sendRichMessage(TranslationManager.get(LanguageString.TROLL_CREDITS, sender, true, entry("target", target.getUsername()))); + target.showCredits(); } case "creeper" -> { - sender.sendRichMessage(TranslationManager.get(LanguageString.TROLL_CREEPER, sender, true, entry("target", target.getName()))); - target.playSound(Sound.sound(Key.key("minecraft:entity.creeper.primed"), Sound.Source.MASTER, 1f, 1f)); + sender.sendRichMessage(TranslationManager.get(LanguageString.TROLL_CREEPER, sender, true, entry("target", target.getUsername()))); + target.sound(Key.key("minecraft:entity.creeper.primed"), Sound.Source.MASTER); } case "demo" -> { - sender.sendRichMessage(TranslationManager.get(LanguageString.TROLL_DEMO, sender, true, entry("target", target.getName()))); - target.showDemoScreen(); + sender.sendRichMessage(TranslationManager.get(LanguageString.TROLL_DEMO, sender, true, entry("target", target.getUsername()))); + target.showDemoPopup(); } case "guardian" -> { - sender.sendRichMessage(TranslationManager.get(LanguageString.TROLL_GUARDIAN, sender, true, entry("target", target.getName()))); + sender.sendRichMessage(TranslationManager.get(LanguageString.TROLL_GUARDIAN, sender, true, entry("target", target.getUsername()))); target.showElderGuardian(); } case "hack" -> { - sender.sendRichMessage(TranslationManager.get(LanguageString.TROLL_HACK, sender, true, entry("target", target.getName()))); + sender.sendRichMessage(TranslationManager.get(LanguageString.TROLL_HACK, sender, true, entry("target", target.getUsername()))); String format = ""; // Ugly but it works - target.getScheduler().execute(Extension.getInstance(), () -> target.showTitle(Title.title( + target.schedule(() -> target.title( MiniMessage.miniMessage().deserialize(format + ":/45v.8r9(VU$R)w.9ruv"), - Component.empty(), - Title.Times.times(Duration.ofMillis(0), Duration.ofSeconds(5), Duration.ofMillis(0)) - )), null, 20); - target.getScheduler().execute(Extension.getInstance(), () -> target.showTitle(Title.title( + null, + Duration.ofMillis(0), + Duration.ofSeconds(5), + Duration.ofMillis(0) + ), 20); + target.schedule(() -> target.title( MiniMessage.miniMessage().deserialize(format + "tI=)$t0,ivAEr9+"), - Component.empty(), - Title.Times.times(Duration.ofMillis(0), Duration.ofSeconds(5), Duration.ofMillis(0)) - )), null, 60); - target.getScheduler().execute(Extension.getInstance(), () -> target.showTitle(Title.title( + null, + Duration.ofMillis(0), + Duration.ofSeconds(5), + Duration.ofMillis(0) + ), 60); + target.schedule(() -> target.title( MiniMessage.miniMessage().deserialize(format + "(U$T98vtiIÜ$)TU9i"), - Component.empty(), - Title.Times.times(Duration.ofMillis(0), Duration.ofSeconds(5), Duration.ofMillis(0)) - )), null, 100); - target.getScheduler().execute(Extension.getInstance(), () -> target.showTitle(Title.title( + null, + Duration.ofMillis(0), + Duration.ofSeconds(5), + Duration.ofMillis(0) + ), 100); + target.schedule(() -> target.title( MiniMessage.miniMessage().deserialize(format + "L.f-.3_F:_34-,ldMVams"), - Component.empty(), - Title.Times.times(Duration.ofMillis(0), Duration.ofSeconds(5), Duration.ofMillis(0)) - )), null, 140); - target.getScheduler().execute(Extension.getInstance(), () -> target.showTitle(Title.title( + null, + Duration.ofMillis(0), + Duration.ofSeconds(5), + Duration.ofMillis(0) + ), 140); + target.schedule(() -> target.title( MiniMessage.miniMessage().deserialize(format + ")$u095u921,EFJKDA"), - Component.empty(), - Title.Times.times(Duration.ofMillis(0), Duration.ofSeconds(5), Duration.ofMillis(0)) - )), null, 180); - target.getScheduler().execute(Extension.getInstance(), () -> target.showTitle(Title.title( + null, + Duration.ofMillis(0), + Duration.ofSeconds(5), + Duration.ofMillis(0) + ), 180); + target.schedule(() -> target.title( MiniMessage.miniMessage().deserialize(format + "joIV;;0p98v"), - Component.empty(), - Title.Times.times(Duration.ofMillis(0), Duration.ofSeconds(5), Duration.ofMillis(0)) - )), null, 220); - target.getScheduler().execute(Extension.getInstance(), () -> target.showTitle(Title.title( + null, + Duration.ofMillis(0), + Duration.ofSeconds(5), + Duration.ofMillis(0) + ), 220); + target.schedule(() -> target.title( MiniMessage.miniMessage().deserialize(format + "IV)=RI(VT=)l9re"), - Component.empty(), - Title.Times.times(Duration.ofMillis(0), Duration.ofSeconds(5), Duration.ofMillis(0)) - )), null, 260); - target.getScheduler().execute(Extension.getInstance(), () -> target.showTitle(Title.title( + null, + Duration.ofMillis(0), + Duration.ofSeconds(5), + Duration.ofMillis(0) + ), 260); + target.schedule(() -> target.title( MiniMessage.miniMessage().deserialize(format + "$KL%98vu9485u20k8lü="), - Component.empty(), - Title.Times.times(Duration.ofMillis(0), Duration.ofSeconds(5), Duration.ofMillis(0)) - )), null, 300); - target.getScheduler().execute(Extension.getInstance(), () -> target.showTitle(Title.title( + null, + Duration.ofMillis(0), + Duration.ofSeconds(5), + Duration.ofMillis(0) + ), 300); + target.schedule(() -> target.title( MiniMessage.miniMessage().deserialize("" + TranslationManager.get(LanguageString.TROLL_HACK_COMPLETE, target, false)), - Component.empty(), - Title.Times.times(Duration.ofMillis(0), Duration.ofSeconds(5), Duration.ofMillis(500)) - )), null, 340); + null, + Duration.ofMillis(0), + Duration.ofSeconds(5), + Duration.ofMillis(500) + ), 340); } case "heavens" -> { - sender.sendRichMessage(TranslationManager.get(LanguageString.TROLL_HEAVENS, sender, true, entry("target", target.getName()))); + sender.sendRichMessage(TranslationManager.get( + LanguageString.TROLL_HEAVENS, + sender, + true, + entry("target", target.getUsername()) + )); Location location = target.getLocation(); location.setY(10000); diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/replacement/GamemodeCommand.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/replacement/GamemodeCommand.java index 819349e..39e7100 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/replacement/GamemodeCommand.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/general/replacement/GamemodeCommand.java @@ -22,16 +22,15 @@ package de.jeremystartm.pickshadow.extension.command.general.replacement; import de.jeremystartm.pickshadow.extension.api.command.Command; import de.jeremystartm.pickshadow.extension.api.command.TabCompletion; import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion; +import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayer; import de.jeremystartm.pickshadow.extension.api.translation.LanguageString; import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager; import lombok.Getter; -import org.bukkit.Bukkit; import org.bukkit.GameMode; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; +import org.bukkit.craftbukkit.command.ServerCommandSender; import org.jetbrains.annotations.NotNull; -import java.util.Objects; +import java.util.Map; import static java.util.Map.entry; @@ -85,22 +84,19 @@ public final class GamemodeCommand extends Command { /** {@inheritDoc} */ @Override - protected void invokeAll(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] arguments) throws Exception { - if (checkPermission(sender, "pickshadow.command.gamemode")) return; - + protected void invokeConsole(@NotNull ServerCommandSender console, @NotNull String alias, @NotNull String[] arguments) throws Exception { // Check length of 'arguments' if (arguments.length == 0) { - sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_TOO_FEW_ARGUMENTS, sender, true)); + console.sendRichMessage(TranslationManager.get(LanguageString.ERROR_TOO_FEW_ARGUMENTS, console, true)); return; } else if (arguments.length > 2) { - sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_TOO_MANY_ARGUMENTS, sender, true)); + console.sendRichMessage(TranslationManager.get(LanguageString.ERROR_TOO_MANY_ARGUMENTS, console, true)); return; } - boolean onSelf; GameMode gamemode; LanguageString gamemodeTranslation; - Player target; + PSPlayer target; // Determine gamemode switch (arguments[0]) { @@ -121,9 +117,9 @@ public final class GamemodeCommand extends Command { gamemodeTranslation = LanguageString.GAMEMODE_SPECTATOR; } default -> { - sender.sendRichMessage(TranslationManager.get( + console.sendRichMessage(TranslationManager.get( LanguageString.ERROR_INVALID_ARGUMENT, - sender, + console, true, entry("argument", arguments[0]) )); @@ -131,60 +127,110 @@ public final class GamemodeCommand extends Command { } } - // Get player - switch (arguments.length) { - case 1 -> { - onSelf = true; + // Determine 'target' + try { + target = determineTarget(console, arguments, 1).getKey(); + } catch (Exception exception) { + return; + } - // Check if command sender is a player - if (sender instanceof Player senderPlayer) - target = senderPlayer; - else { - sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_NOT_A_PLAYER, sender, true)); - return; - } + // Set gamemode + updateTargetGamemode(target, gamemode, gamemodeTranslation); + + // Send success message to console + console.sendRichMessage(TranslationManager.get( + LanguageString.GAMEMODE_REMOTE, + console, + true, + entry("player", target.getUsername()), + entry("gamemode", TranslationManager.get(gamemodeTranslation, target, false)) + )); + } + + /** {@inheritDoc} */ + @Override + protected void invokePlayer(@NotNull PSPlayer player, @NotNull String alias, @NotNull String[] arguments) throws Exception { + if (checkPermission(player, "pickshadow.command.gamemode")) return; + + // Check length of 'arguments' + if (arguments.length == 0) { + player.messageTranslatable(LanguageString.ERROR_TOO_FEW_ARGUMENTS, true); + return; + } else if (arguments.length > 2) { + player.messageTranslatable(LanguageString.ERROR_TOO_MANY_ARGUMENTS, true); + return; + } + + GameMode gamemode; + LanguageString gamemodeTranslation; + PSPlayer target; + boolean onSelf; + + // Determine gamemode + switch (arguments[0]) { + case "0", "survival" -> { + gamemode = GameMode.SURVIVAL; + gamemodeTranslation = LanguageString.GAMEMODE_SURVIVAL; } - case 2 -> { - target = Bukkit.getPlayer(arguments[1]); - try { - onSelf = Objects.requireNonNull(target).getName().equals(sender.getName()); - } catch (NullPointerException exception) { - onSelf = false; - } - - // Check if 'target' is null - if (target == null) { - sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_PLAYER_NOT_FOUND, - sender, - true, - entry("player", arguments[1]) - )); - return; - } + case "1", "creative" -> { + gamemode = GameMode.CREATIVE; + gamemodeTranslation = LanguageString.GAMEMODE_CREATIVE; + } + case "2", "adventure" -> { + gamemode = GameMode.ADVENTURE; + gamemodeTranslation = LanguageString.GAMEMODE_ADVENTURE; + } + case "3", "spectator" -> { + gamemode = GameMode.SPECTATOR; + gamemodeTranslation = LanguageString.GAMEMODE_SPECTATOR; } default -> { - sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_TOO_MANY_ARGUMENTS, sender, true)); + player.messageTranslatable( + LanguageString.ERROR_INVALID_ARGUMENT, + true, + entry("argument", arguments[0]) + ); return; } } - // Set game mode - target.setGameMode(gamemode); + // Determine 'target' and 'onSelf' + try { + Map.Entry<@NotNull PSPlayer, @NotNull Boolean> targetEntry = determineTarget(player, arguments, 1); + target = targetEntry.getKey(); + onSelf = targetEntry.getValue(); + } catch (Exception exception) { + return; + } + + // Set gamemode + updateTargetGamemode(target, gamemode, gamemodeTranslation); + + // Send success message to sender + if (!onSelf) + player.messageTranslatable( + LanguageString.GAMEMODE_REMOTE, + true, + entry("player", target.getUsername()), + entry("gamemode", TranslationManager.get(gamemodeTranslation, target, false)) + ); + } + + /** + * Updates the gamemode of the specified target player. + * + * @param target target player to update the gamemode for + * @param gamemode gamemode to switch to + * @param gamemodeTranslation matching {@link LanguageString} for the specified gamemode + */ + private static void updateTargetGamemode(@NotNull PSPlayer target, @NotNull GameMode gamemode, @NotNull LanguageString gamemodeTranslation) { + target.setGamemode(gamemode); // Send message - target.sendRichMessage(TranslationManager.get( + target.messageTranslatable( LanguageString.GAMEMODE, - target, true, entry("gamemode", TranslationManager.get(gamemodeTranslation, target, false)) - )); - if (!onSelf) - sender.sendRichMessage(TranslationManager.get( - LanguageString.GAMEMODE_REMOTE, - sender, - true, - entry("player", target.getName()), - entry("gamemode", TranslationManager.get(gamemodeTranslation, target, false)) - )); + ); } } diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/survival/HomeCommand.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/survival/HomeCommand.java index efedad5..aab445f 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/survival/HomeCommand.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/survival/HomeCommand.java @@ -20,17 +20,16 @@ package de.jeremystartm.pickshadow.extension.command.survival; import de.jeremystartm.pickshadow.extension.api.command.Command; -import de.jeremystartm.pickshadow.extension.api.command.completion.StubTabCompletion; +import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion; import de.jeremystartm.pickshadow.extension.api.command.TabCompletion; +import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayer; import de.jeremystartm.pickshadow.extension.api.translation.LanguageString; import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager; import lombok.Getter; -import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; +import org.bukkit.craftbukkit.command.ServerCommandSender; import org.jetbrains.annotations.NotNull; -import java.util.Objects; +import java.util.Map; import static java.util.Map.entry; @@ -52,7 +51,8 @@ public final class HomeCommand extends Command { * @return tab completion * @since v1-release0 */ - private final @NotNull TabCompletion completion = StubTabCompletion.completion(); + private final @NotNull TabCompletion completion = new StaticTabCompletion() + .players("", 0); /** * Creates and initializes an instance of @@ -74,64 +74,83 @@ public final class HomeCommand extends Command { /** {@inheritDoc} */ @Override - protected void invokeAll(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] arguments) { - if (checkPermission(sender, "pickshadow.command.home")) return; + protected void invokeConsole(@NotNull ServerCommandSender console, @NotNull String alias, @NotNull String @NotNull [] arguments) { + PSPlayer target; - boolean onSelf; - Player player; - - // Get player - switch (arguments.length) { - case 0 -> { - onSelf = true; - - // Check if command sender is a player - if (sender instanceof Player senderPlayer) - player = senderPlayer; - else { - sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_NOT_A_PLAYER, sender, true)); - return; - } - } - case 1 -> { - player = Bukkit.getPlayer(arguments[0]); - try { - onSelf = !Objects.requireNonNull(player).getName().equals(sender.getName()); - } catch (NullPointerException exception) { - onSelf = false; - } - - // Check if 'player' is null - if (player == null) { - sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_PLAYER_NOT_FOUND, - sender, - true, - entry("player", arguments[0]) - )); - return; - } - } - default -> { - sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_TOO_MANY_ARGUMENTS, sender, true)); - return; - } + // Parse arguments + try { + target = determineTarget(console, arguments, 0).getKey(); + } catch (Exception exception) { + return; } - // Teleport player - if (player.getRespawnLocation() == null) - if (onSelf) - sender.sendRichMessage(TranslationManager.get(LanguageString.HOME_NORESPAWN, sender, true)); - else - sender.sendRichMessage(TranslationManager.get( - LanguageString.HOME_NORESPAWN_OTHER, - sender, + if (teleportTarget(target)) + console.sendRichMessage(TranslationManager.get( + LanguageString.HOME_OTHER, + console, + true, + entry("target", target.getUsername()) + )); + else + console.sendRichMessage(TranslationManager.get( + LanguageString.HOME_NORESPAWN_OTHER, + console, + true, + entry("target", target.getUsername()) + )); + } + + /** {@inheritDoc} */ + @Override + protected void invokePlayer(@NotNull PSPlayer player, @NotNull String alias, @NotNull String @NotNull [] arguments) { + if (checkPermission(player, "pickshadow.command.home")) return; + + PSPlayer target; + boolean onSelf; + + // Parse arguments + try { + Map.Entry<@NotNull PSPlayer, @NotNull Boolean> targetEntry = determineTarget(player, arguments, 0); + target = targetEntry.getKey(); + onSelf = targetEntry.getValue(); + } catch (Exception exception) { + return; + } + + if (teleportTarget(target)) { + if (!onSelf) + player.messageTranslatable( + LanguageString.HOME_OTHER, true, - entry("player", player.getName()) - )); + entry("target", target.getUsername()) + ); + } else + if (onSelf) + player.messageTranslatable(LanguageString.HOME_NORESPAWN, true); + else + player.messageTranslatable( + LanguageString.HOME_NORESPAWN_OTHER, + true, + entry("target", target.getUsername()) + ); + } + + /** + * Teleports the specified target player to their respawn point. + * + * @param target target to teleport + * @return teleportation successful? + * @since v1-release0 + */ + private static boolean teleportTarget(@NotNull PSPlayer target) { + // Teleport target + if (target.getRespawnLocation() == null) + return false; else { - player.teleport(player.getRespawnLocation()); - player.setFallDistance(0f); - sender.sendRichMessage(TranslationManager.get(LanguageString.HOME, sender, true)); + target.teleport(target.getRespawnLocation()); + target.setFallDistance(0f); + target.messageTranslatable(LanguageString.HOME, true); + return true; } } } diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/survivalcheat/FeedCommand.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/survivalcheat/FeedCommand.java index 93c5579..699834d 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/survivalcheat/FeedCommand.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/survivalcheat/FeedCommand.java @@ -22,15 +22,14 @@ package de.jeremystartm.pickshadow.extension.command.survivalcheat; import de.jeremystartm.pickshadow.extension.api.command.Command; import de.jeremystartm.pickshadow.extension.api.command.TabCompletion; import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion; +import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayer; import de.jeremystartm.pickshadow.extension.api.translation.LanguageString; import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager; import lombok.Getter; -import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; +import org.bukkit.craftbukkit.command.ServerCommandSender; import org.jetbrains.annotations.NotNull; -import java.util.Objects; +import java.util.*; import static java.util.Map.entry; @@ -73,63 +72,70 @@ public final class FeedCommand extends Command { ), "feed"); } + /** {@inheritDoc} */ + protected void invokeConsole(@NotNull ServerCommandSender console, @NotNull String alias, @NotNull String @NotNull [] arguments) { + PSPlayer target; + + // Parse arguments + try { + target = determineTarget(console, arguments, 0).getKey(); + } catch (Exception exception) { + return; + } + + // Heal target + feedTarget(target); + + // Send success message to console + console.sendRichMessage(TranslationManager.get( + LanguageString.HEAL_REMOTE, + console, + true, + entry("player", target.getUsername()) + )); + } + /** {@inheritDoc} */ @Override - protected void invokeAll(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] arguments) { - if (checkPermission(sender, "pickshadow.command.feed")) return; - - Player player; + protected void invokePlayer(@NotNull PSPlayer player, @NotNull String alias, @NotNull String @NotNull [] arguments) { + if (checkPermission(player, "pickshadow.command.heal")) return; + PSPlayer target; boolean onSelf; - // Get player - switch (arguments.length) { - case 0 -> { - onSelf = true; - - // Check if command sender is a player - if (sender instanceof Player senderPlayer) - player = senderPlayer; - else { - sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_NOT_A_PLAYER, sender, true)); - return; - } - } - case 1 -> { - player = Bukkit.getPlayer(arguments[0]); - try { - onSelf = Objects.requireNonNull(player).getName().equals(sender.getName()); - } catch (NullPointerException exception) { - onSelf = false; - } - - // Check if 'player' is null - if (player == null) { - sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_PLAYER_NOT_FOUND, - sender, - true, - entry("player", arguments[0]) - )); - return; - } - } - default -> { - sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_TOO_MANY_ARGUMENTS, sender, true)); - return; - } + // Parse arguments + try { + Map.Entry<@NotNull PSPlayer, @NotNull Boolean> targetEntry = determineTarget(player, arguments, 0); + target = targetEntry.getKey(); + onSelf = targetEntry.getValue(); + } catch (Exception exception) { + return; } // Heal player - player.setFoodLevel(20); + feedTarget(target); + + // Send success message to sender + if (!onSelf) + player.messageTranslatable( + LanguageString.FEED_REMOTE, + true, + entry("player", target.getUsername()) + ); + } + + /** + * Heals the specified target player. + * + * @param target target player to heal + * @since v1-release0 + */ + private static void feedTarget(@NotNull PSPlayer target) { + // Heal + target.setHunger(20); + target.setSaturation(20); // Send success message - player.sendRichMessage(TranslationManager.get(LanguageString.FEED, player, true)); - if (!onSelf) - sender.sendRichMessage(TranslationManager.get( - LanguageString.FEED_REMOTE, - sender, - true, - entry("player", player.getName()) - )); + target.messageTranslatable(LanguageString.FEED, true); } } diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/survivalcheat/HealCommand.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/survivalcheat/HealCommand.java index d936aaa..ea32afb 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/survivalcheat/HealCommand.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/command/survivalcheat/HealCommand.java @@ -23,22 +23,18 @@ import de.jeremystartm.pickshadow.extension.BuildOptions; import de.jeremystartm.pickshadow.extension.api.command.Command; import de.jeremystartm.pickshadow.extension.api.command.TabCompletion; import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion; +import de.jeremystartm.pickshadow.extension.api.entity.player.PSPlayer; import de.jeremystartm.pickshadow.extension.api.translation.LanguageString; import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager; import lombok.Getter; -import org.bukkit.Bukkit; import org.bukkit.attribute.Attribute; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; +import org.bukkit.craftbukkit.command.ServerCommandSender; import org.bukkit.event.entity.EntityRegainHealthEvent; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; +import java.util.*; import static java.util.Map.entry; @@ -84,77 +80,90 @@ public final class HealCommand extends Command { } /** {@inheritDoc} */ - @Override - protected void invokeAll(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] arguments) { - if (checkPermission(sender, "pickshadow.command.heal")) return; - - Player player; + protected void invokeConsole(@NotNull ServerCommandSender console, @NotNull String alias, @NotNull String @NotNull [] arguments) { List<@NotNull String> argumentsList = new ArrayList<>(Arrays.stream(arguments).toList()); + boolean allEffects; + boolean keepEffects; + PSPlayer target; - boolean onSelf; - boolean keepEffects = argumentsList.remove("--keep-effects"); + // Parse arguments + try { + allEffects = argumentsList.remove("--all-effects"); + keepEffects = argumentsList.remove("--keep-effects"); + target = determineTarget(console, argumentsList.toArray(new String[0]), 0).getKey(); + } catch (Exception exception) { + return; + } + + // Heal target + healTarget(target, allEffects, keepEffects); + + // Send success message to console + console.sendRichMessage(TranslationManager.get( + LanguageString.HEAL_REMOTE, + console, + true, + entry("player", target.getUsername()) + )); + } + + /** {@inheritDoc} */ + @Override + protected void invokePlayer(@NotNull PSPlayer player, @NotNull String alias, @NotNull String @NotNull [] arguments) { + if (checkPermission(player, "pickshadow.command.heal")) return; + + List<@NotNull String> argumentsList = new ArrayList<>(Arrays.stream(arguments).toList()); boolean allEffects = argumentsList.remove("--all-effects"); + boolean keepEffects = argumentsList.remove("--keep-effects"); + PSPlayer target; + boolean onSelf; - // Get player - switch (argumentsList.size()) { - case 0 -> { - onSelf = true; - - // Check if command sender is a player - if (sender instanceof Player senderPlayer) - player = senderPlayer; - else { - sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_NOT_A_PLAYER, sender, true)); - return; - } - } - case 1 -> { - player = Bukkit.getPlayer(argumentsList.getFirst()); - try { - onSelf = Objects.requireNonNull(player).getName().equals(sender.getName()); - } catch (NullPointerException exception) { - onSelf = false; - } - - // Check if 'player' is null - if (player == null) { - sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_PLAYER_NOT_FOUND, - sender, - true, - entry("player", argumentsList.getFirst()) - )); - return; - } - } - default -> { - sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_TOO_MANY_ARGUMENTS, sender, true)); - return; - } + // Parse arguments + try { + Map.Entry<@NotNull PSPlayer, @NotNull Boolean> targetEntry = determineTarget(player, argumentsList.toArray(new String[0]), 0); + target = targetEntry.getKey(); + onSelf = targetEntry.getValue(); + } catch (Exception exception) { + return; } // Heal player - player.heal(Objects.requireNonNull(player.getAttribute(Attribute.MAX_HEALTH)).getValue() - player.getHealth(), EntityRegainHealthEvent.RegainReason.MAGIC); - player.setFoodLevel(20); - player.setSaturation(20); - player.setRemainingAir(300); + healTarget(target, allEffects, keepEffects); + + // Send success message to sender + if (!onSelf) + player.messageTranslatable( + LanguageString.HEAL_REMOTE, + true, + entry("player", target.getUsername()) + ); + } + + /** + * Heals the specified target player. + * + * @param target target player to heal + * @param allEffects whether to remove all effects + * @param keepEffects whether to keep all effects + * @since v1-release0 + */ + private static void healTarget(@NotNull PSPlayer target, boolean allEffects, boolean keepEffects) { + // Heal + target.heal(Objects.requireNonNull(target.getAttribute(Attribute.MAX_HEALTH)).getValue() - target.getHealth(), EntityRegainHealthEvent.RegainReason.MAGIC); + target.setHunger(20); + target.setSaturation(20); + target.setAirLeft(300); // Reset bad or all effects if (!keepEffects) if (allEffects) - for (PotionEffect effect : player.getActivePotionEffects()) - player.removePotionEffect(effect.getType()); + for (PotionEffect effect : target.getPotions()) + target.removePotion(effect.getType()); else for (PotionEffectType effectType : BuildOptions.SETTINGS_EFFECTS_DAMAGING) - player.removePotionEffect(effectType); + target.removePotion(effectType); // Send success message - player.sendRichMessage(TranslationManager.get(LanguageString.HEAL, player, true)); - if (!onSelf) - sender.sendRichMessage(TranslationManager.get( - LanguageString.HEAL_REMOTE, - sender, - true, - entry("player", player.getName()) - )); + target.messageTranslatable(LanguageString.HEAL, true); } } diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/listener/ChatListener.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/listener/ChatListener.java index 69c164e..edde167 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/listener/ChatListener.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/listener/ChatListener.java @@ -68,20 +68,18 @@ public final class ChatListener implements Listener { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void handleChatMessage(@NotNull AsyncChatEvent event) { PSPlayer player = PSPlayerFactory.get(event.getPlayer()); + String message = MiniMessage.miniMessage().serialize(event.originalMessage()); // Cancel chat message event.setCancelled(true); // Broadcast the message ourselves - if (!BuildOptions.SMALLSTUFF_CHAT_COMMENTS || !MiniMessage.miniMessage().serialize(event.originalMessage()).startsWith("#")) - PSPlayer.broadcast( - TranslationManager.get( - LanguageString.MESSAGING_SERVER, - player.getBukkitPlayer(), - false, - entry("sender", player.getUsername()) - ) - + MiniMessage.miniMessage().serialize(event.originalMessage()).replace("\\<", "<") + if (!BuildOptions.SMALLSTUFF_CHAT_COMMENTS || !message.startsWith("#")) + PSPlayer.broadcastTranslatable( + LanguageString.MESSAGING_SERVER, + false, + entry("sender", player.getUsername()), + entry("message", message.replace("\\<", "<")) ); } diff --git a/extension/src/main/java/de/jeremystartm/pickshadow/extension/misc/DamageDetection.java b/extension/src/main/java/de/jeremystartm/pickshadow/extension/misc/DamageDetection.java index ff282e7..d2d085e 100644 --- a/extension/src/main/java/de/jeremystartm/pickshadow/extension/misc/DamageDetection.java +++ b/extension/src/main/java/de/jeremystartm/pickshadow/extension/misc/DamageDetection.java @@ -68,7 +68,7 @@ public final class DamageDetection { if (BuildOptions.SMALLSTUFF_STONECUTTER_DAMAGE) switch (player.getData().getDamageState(STONECUTTER)) { case -1 -> { - Location location = player.getPosition().clone(); + Location location = player.getLocation().clone(); location.setX((long) location.getX() - 1); location.setY(((long) location.getY())); location.setZ((long) location.getZ()); diff --git a/extension/src/main/resources/translations/de.json b/extension/src/main/resources/translations/de.json index 769e7b4..fe5d9d8 100644 --- a/extension/src/main/resources/translations/de.json +++ b/extension/src/main/resources/translations/de.json @@ -29,10 +29,10 @@ "MESSAGING_ERROR_NOLASTCONTACT": "Du hast in der letzten Zeit keinen angeschrieben.", "LINKS_WEBSITE": "Das PickShadow Netzwerk hat aktuell keine Webseite.", - "LINKS_FORUM": "Das PickShadow Netzwerk hat aktuell kein Forum.", - "LINKS_DISCORD": "Das PickShadow Netzwerk hat aktuell keine Discord Guilde.", - "LINKS_TEAMSPEAK": "Das PickShadow Netzwerk hat aktuell keinen TeamSpeak Server.", + "LINKS_MESSAGEBOARD": "Das PickShadow Netzwerk hat aktuell kein Forum.", "LINKS_MUMBLE": "Das PickShadow Netzwerk hat aktuell keinen Mumble Server.", + "LINKS_TEAMSPEAK": "Das PickShadow Netzwerk hat aktuell keinen TeamSpeak Server.", + "LINKS_DISCORD": "Das PickShadow Netzwerk hat aktuell keine Discord Guilde.", "CLEARCHAT_GENERIC": "Der Chat wurde von %sender% geleert.", "CLEARCHAT_VOID": "Der Chat wurde von %sender% ins Void geschubst.", @@ -40,6 +40,7 @@ "CLEARCHAT_BRAINDAMAGE": "Um weitverbreitenden Gehirnschaden zu verhinden, hat %sender% den Chat geleert.", "CLEARCHAT_CRINGE": "Aufgrund von Massen an Cringe musste %sender% den Chat leeren.", + "HOME_OTHER": "%target% wurde zu seinem/ihrem Respawnpunkt teleportiert.", "HOME_NORESPAWN": "Du hast keinen gültigen Respawnpunkt.\nStelle sicher, dass dein Bett oder Respawn Anker nicht abgebaut oder behindert ist.", "HOME_NORESPAWN_OTHER": "%player% hat keinen gültigen Respawnpunkt.\n%player%'s Bett oder Respawn Anker wurde entweder abgebaut oder ist behindert.", diff --git a/extension/src/main/resources/translations/en.json b/extension/src/main/resources/translations/en.json index 63a0217..b74030b 100644 --- a/extension/src/main/resources/translations/en.json +++ b/extension/src/main/resources/translations/en.json @@ -36,17 +36,17 @@ "LEGACYEXTENSIONCMD": "What's PSSP...?\nThe PickShadow Server Plugin (PSSP) has been renamed into PickShadow Server Extension (PSSE).\nPlease use the new name from now on. Thank you.", - "MESSAGING_SERVER": "%sender% <#d60532>» ", + "MESSAGING_SERVER": "%sender% <#d60532>» %message%", "MESSAGING_DIRECT": "%from% » %to% » %message%", "MESSAGING_LASTCONTACT": "The last person you've messaged is %contact%.", "MESSAGING_ERROR_SELF": "You can't message yourself.", "MESSAGING_ERROR_NOLASTCONTACT": "You haven't messaged anyone recently.", "LINKS_WEBSITE": "The PickShadow Network doesn't currently have a website.", - "LINKS_FORUM": "The PickShadow Network doesn't currently have a forum.", - "LINKS_DISCORD": "The PickShadow Network doesn't currently have a Discord guild.", - "LINKS_TEAMSPEAK": "The PickShadow Network doesn't currently have a TeamSpeak server.", + "LINKS_MESSAGEBOARD": "The PickShadow Network doesn't currently have a forum.", "LINKS_MUMBLE": "The PickShadow Network doesn't currently have a Mumble server.", + "LINKS_TEAMSPEAK": "The PickShadow Network doesn't currently have a TeamSpeak server.", + "LINKS_DISCORD": "The PickShadow Network doesn't currently have a Discord guild.", "CLEARCHAT_GENERIC": "The chat has been cleared by %sender%.", "CLEARCHAT_VOID": "The chat has been pushed into the void by %sender%.", @@ -55,6 +55,7 @@ "CLEARCHAT_CRINGE": "Due to masses of cringe, %sender% had to clear the chat.", "HOME": "... woosh ...", + "HOME_OTHER": "%target% was teleported to their spawn point.", "HOME_NORESPAWN": "You do not have a valid respawn point.\nPlease make sure your bed or respawn anchor isn't missing or obstructed.", "HOME_NORESPAWN_OTHER": "%player% does not have a valid respawn point.\n%player%'s bed or respawn anchor is either missing or obstructed.", @@ -76,6 +77,9 @@ "HEAL": "You have been healed.", "HEAL_REMOTE": "%player% has been healed.", + "FEED": "You have been fed.", + "FEED_REMOTE": "%player% has been fed.", + "PLUGINS": "%count% extensions are installed on this subserver, these being:", "PLUGINS_FAKE": "Do you really think you can get internal information so easily?\nLuckily, we aren't dicks and credit what we use.\nThe PickShadow network uses PSSE, LuckPerms, ViaVersion and FreedomChat to manage subservers.", "PLUGINS_ENTRY_PREFIX": "- ",