feat: add some *base* placeholders and util classes

This commit is contained in:
iGabyTM committed 2023-12-31 12:43:33 +02:00
1 parent 7a85f43bb6
commit 658a76873c
4 files changed
+478

No files matched your search

@@ -0,0 +1,291 @@
package at.helpch.placeholderapi.expansion.player;
import at.helpch.placeholderapi.expansion.player.util.ItemUtil;
import at.helpch.placeholderapi.expansion.player.util.PlayerUtil;
import at.helpch.placeholderapi.expansion.player.util.VersionHelper;
import com.google.common.collect.ImmutableMap;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.expansion.Configurable;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Date;
import java.util.Map;
import java.util.Optional;
public final class PlayerExpansion extends PlaceholderExpansion implements Configurable {
@Override
public @NotNull String getIdentifier() {
return "player";
}
@Override
public @NotNull String getAuthor() {
return "HelpChat";
}
@Override
public @NotNull String getVersion() {
return "3.0.0";
}
@Override
public Map<String, Object> getDefaults() {
return ImmutableMap.<String, Object>builder()
.put("ping_color.high", "&c")
.put("ping_color.medium", "&e")
.put("ping_color.low", "&a")
.put("ping_value.medium", 50)
.put("ping_value.high", 100)
.put("direction.north", "N")
.put("direction.north_east", "NE")
.put("direction.east", "E")
.put("direction.south_east", "SE")
.put("direction.south", "S")
.put("direction.south_west", "SW")
.put("direction.west", "W")
.put("direction.north_west", "NW")
.build();
}
@Override
public boolean canRegister() {
return true;
}
/**
* Format a {@code boolean} as {@link PlaceholderAPIPlugin#booleanTrue()} or {@link PlaceholderAPIPlugin#booleanFalse()}
*
* @param bool boolean
* @return {@link PlaceholderAPIPlugin#booleanTrue()} if the boolean is true, otherwise {@link PlaceholderAPIPlugin#booleanFalse()}
*/
private @NotNull String bool(final boolean bool) {
return bool ? PlaceholderAPIPlugin.booleanTrue() : PlaceholderAPIPlugin.booleanFalse();
}
private @NotNull String getItemInfo(@Nullable final ItemStack item, @NotNull final String args) {
switch (args) {
case "_name":
return ItemUtil.getName(item);
case "_data":
return String.valueOf(ItemUtil.getData(item));
case "_durability":
return String.valueOf(ItemUtil.getDurability(item));
default:
return ItemUtil.getMaterialName(item);
}
}
@SuppressWarnings("SpellCheckingInspection")
@Override
public @Nullable String onRequest(OfflinePlayer offlinePlayer, @NotNull String params) {
//TODO: add target ping placeholders
if (offlinePlayer == null) {
return "";
}
switch (params) {
case "name":
return offlinePlayer.getName();
case "uuid":
return offlinePlayer.getUniqueId().toString();
case "has_played_before":
return bool(offlinePlayer.hasPlayedBefore());
case "is_whitelisted":
return bool(offlinePlayer.isWhitelisted());
case "is_banned":
return bool(offlinePlayer.isBanned());
case "is_op":
return bool(offlinePlayer.isOnline());
case "first_played":
case "first_join":
return String.valueOf(offlinePlayer.getFirstPlayed());
case "first_played_formatted":
case "first_join_date":
return PlaceholderAPIPlugin.getDateFormat().format(new Date(offlinePlayer.getFirstPlayed()));
case "last_played":
case "last_join":
//noinspection deprecation
return String.valueOf(offlinePlayer.getLastPlayed());
case "last_played_formatted":
case "last_join_date":
//noinspection deprecation
return PlaceholderAPIPlugin.getDateFormat().format(new Date(offlinePlayer.getLastPlayed()));
//<editor-fold desc="Bed location placeholders">
case "bed_x":
return PlayerUtil.getBedCoordinate(offlinePlayer, Location::getX);
case "bed_y":
return PlayerUtil.getBedCoordinate(offlinePlayer, Location::getY);
case "bed_z":
return PlayerUtil.getBedCoordinate(offlinePlayer, Location::getZ);
case "bed_world":
return Optional.ofNullable(offlinePlayer.getBedSpawnLocation())
.map(Location::getWorld)
.map(World::getName)
.orElse("");
//</editor-fold>
}
if (!offlinePlayer.isOnline()) {
return "";
}
final Player player = offlinePlayer.getPlayer();
// To get rid of IDE warnings
if (player == null) {
return "";
}
switch (params) {
case "displayname":
//noinspection deprecation
return player.getDisplayName();
case "custom_name":
return Optional.ofNullable(player.getCustomName()).orElseGet(player::getName);
case "list_name":
//noinspection deprecation
return player.getPlayerListName();
case "gamemode":
return player.getGameMode().name();
//<editor-fold desc="Location / position placeholders">
//TODO: add direction and direction_xz
case "world":
return player.getWorld().getName();
case "world_type": {
final World.Environment environment = player.getWorld().getEnvironment();
if (environment == World.Environment.NETHER) {
return "Nether";
} else if (environment == World.Environment.THE_END) {
return "The End";
} else if (environment == World.Environment.NORMAL) {
return "Overworld";
} else {
return "";
}
}
case "x":
return String.valueOf(player.getLocation().getBlockX());
case "x_long":
return String.valueOf(player.getLocation().getX());
case "y":
return String.valueOf(player.getLocation().getBlockY());
case "y_long":
return String.valueOf(player.getLocation().getY());
case "z":
return String.valueOf(player.getLocation().getBlockZ());
case "z_long":
return String.valueOf(player.getLocation().getZ());
case "yaw":
return String.valueOf(player.getLocation().getYaw());
case "pitch":
return String.valueOf(player.getLocation().getPitch());
case "block_underneath":
return String.valueOf(
player.getLocation()
.clone()
.subtract(0, 1, 0)
.getBlock()
.getType()
);
case "compass_x":
return PlayerUtil.getCompassCoordinate(player, Location::getBlockX);
case "compass_y":
return PlayerUtil.getCompassCoordinate(player, Location::getBlockY);
case "compass_z":
return PlayerUtil.getCompassCoordinate(player, Location::getBlockZ);
case "compass_world":
//noinspection OptionalOfNullableMisuse
return Optional.ofNullable(player.getCompassTarget())
.map(Location::getWorld)
.map(World::getName)
.orElse("");
//</editor-fold>
//TODO: exp placeholders
case "fly_speed":
return String.valueOf(player.getFlySpeed());
case "food_level":
return String.valueOf(player.getFoodLevel());
case "health":
return String.valueOf(player.getHealth());
case "health_rounded":
return String.valueOf(Math.round(player.getHealth()));
case "health_scale":
return String.valueOf(player.getHealthScale());
case "has_health_boost":
return bool(player.hasPotionEffect(PotionEffectType.HEALTH_BOOST));
case "health_boost": {
if (player.getHealthScale() > 20) {
return Double.toString(player.getHealthScale() - 20);
} else {
return "0";
}
}
case "absorption": {
if (VersionHelper.HAS_ABSORPTION_METHODS) {
return String.valueOf((int) player.getAbsorptionAmount());
} else {
return "-1";
}
}
//<editor-fold desc="Inventory placeholders">
case "has_empty_slot":
return bool(player.getInventory().firstEmpty() > -1);
case "empty_slots":
return String.valueOf(PlayerUtil.getEmptySlots(player));
case "item_in_hand":
case "item_in_hand_name":
case "item_in_hand_data":
case "item_in_hand_durability":
return getItemInfo(PlayerUtil.getItemInMainHand(player), params.substring("item_in_hand".length()));
case "item_in_offhand":
case "item_in_offhand_name":
case "item_in_offhand_data":
case "item_in_offhand_durability":
return getItemInfo(player.getInventory().getItemInOffHand(), params.substring("item_in_offhand".length()));
case "armor_helmet":
case "armor_helmet_name":
case "armor_helmet_data":
case "armor_helmet_durability":
return getItemInfo(player.getInventory().getHelmet(), params.substring("armor_helmet".length()));
case "armor_chestplate":
case "armor_chestplate_name":
case "armor_chestplate_data":
case "armor_chestplate_durability":
return getItemInfo(player.getInventory().getChestplate(), params.substring("armor_chestplate".length()));
case "armor_leggings":
case "armor_leggings_name":
case "armor_leggings_data":
case "armor_leggings_durability":
return getItemInfo(player.getInventory().getLeggings(), params.substring("armor_leggings".length()));
case "armor_boots":
case "armor_boots_name":
case "armor_boots_data":
case "armor_boots_durability":
return getItemInfo(player.getInventory().getBoots(), params.substring("armor_boots".length()));
//</editor-fold>
}
return super.onRequest(offlinePlayer, params);
}
}
@@ -0,0 +1,44 @@
package at.helpch.placeholderapi.expansion.player.util;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.Damageable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public final class ItemUtil {
public static boolean isNullOrAir(@Nullable final ItemStack itemStack) {
return itemStack == null || itemStack.getType().name().contains("_AIR");
}
public static @NotNull String getMaterialName(@Nullable final ItemStack item) {
return isNullOrAir(item) ? "" : item.getType().name();
}
public static @NotNull String getName(@Nullable final ItemStack item) {
if (isNullOrAir(item)) {
return "";
}
//noinspection deprecation
return item.hasItemMeta() ? item.getItemMeta().getDisplayName() : "";
}
public static int getData(@Nullable final ItemStack item) {
if (isNullOrAir(item)) {
return 0;
}
if (VersionHelper.HAS_DAMAGEABLE_ITEM_META) {
return item.hasItemMeta() ? ((Damageable) item.getItemMeta()).getDamage() : 0;
} else {
//noinspection deprecation
return item.getDurability();
}
}
public static int getDurability(@Nullable final ItemStack item) {
return isNullOrAir(item) ? 0 : item.getType().getMaxDurability() - getData(item);
}
}
@@ -0,0 +1,70 @@
package at.helpch.placeholderapi.expansion.player.util;
import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
public final class PlayerUtil {
private static final BlockFace[] radial = {
BlockFace.NORTH, BlockFace.NORTH_EAST,
BlockFace.EAST, BlockFace.SOUTH_EAST,
BlockFace.SOUTH, BlockFace.SOUTH_WEST,
BlockFace.WEST, BlockFace.NORTH_WEST
};
@SuppressWarnings({"DataFlowIssue", "deprecation"})
public static @Nullable ItemStack getItemInMainHand(@NotNull final Player player) {
return VersionHelper.HAS_OFF_HAND ? player.getInventory().getItemInMainHand() : player.getItemInHand();
}
public static @NotNull String getBedCoordinate(
@NotNull final OfflinePlayer player, @NotNull final Function<@NotNull Location, @NotNull Number> function
) {
return Optional.ofNullable(player.getBedSpawnLocation())
.map(function)
.map(String::valueOf)
.orElse("0");
}
@SuppressWarnings("OptionalOfNullableMisuse")
public static @NotNull String getCompassCoordinate(
@NotNull final Player player, @NotNull final Function<@NotNull Location, @NotNull Number> function
) {
return Optional.ofNullable(player.getCompassTarget())
.map(function)
.map(String::valueOf)
.orElse("0");
}
public static int getEmptySlots(@NotNull final Player player) {
final PlayerInventory inventory = player.getInventory();
final List<ItemStack> items = new ArrayList<>(Arrays.asList(inventory.getContents()));
items.add(inventory.getHelmet());
items.add(inventory.getChestplate());
items.add(inventory.getLeggings());
items.add(inventory.getBoots());
if (VersionHelper.HAS_OFF_HAND) {
items.add(inventory.getItemInOffHand());
}
return (int) items.stream().filter(ItemUtil::isNullOrAir).count();
}
public static @NotNull BlockFace getDirection(@NotNull final Player player) {
return radial[Math.round(player.getLocation().getYaw() / 45f) & 0x7].getOppositeFace();
}
}
@@ -0,0 +1,73 @@
package at.helpch.placeholderapi.expansion.player.util;
import com.google.common.primitives.Ints;
import org.bukkit.Bukkit;
import org.bukkit.entity.Damageable;
import org.bukkit.entity.Player;
import org.bukkit.inventory.PlayerInventory;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Matt (<a href="https://github.com/lichthund">@LichtHund</a>)
*/
public final class VersionHelper {
private static final int VERSION = getCurrentVersion();
/**
* @see PlayerInventory#getItemInOffHand()
* @since MC 1.9
*/
public static final boolean HAS_OFF_HAND = VERSION >= 1_9_0;
/**
* @see org.bukkit.inventory.meta.Damageable
* @since MC 1.13
*/
public static final boolean HAS_DAMAGEABLE_ITEM_META = VERSION >= 1_13_0;
/**
* @see Damageable#getAbsorptionAmount()
* @since MC 1.15
*/
public static final boolean HAS_ABSORPTION_METHODS = VERSION >= 1_15_0;
/**
* @see Player#getPing()
* @since MC 1.17
*/
public static final boolean HAS_PLAYER_PING_METHOD = VERSION >= 1_17_0;
private VersionHelper() { }
/**
* Gets the current server version
*
* @return A protocol like number representing the version, for example 1.16.5 - 1165
*/
private static int getCurrentVersion() {
// No need to cache since will only run once
final Matcher matcher = Pattern.compile("(?<version>\\d+\\.\\d+)(?<patch>\\.\\d+)?").matcher(Bukkit.getBukkitVersion());
final StringBuilder stringBuilder = new StringBuilder();
if (matcher.find()) {
final String patch = matcher.group("patch");
stringBuilder
.append(matcher.group("version").replace(".", ""))
.append((patch == null) ? "0" : patch.replace(".", ""));
}
final Integer version = Ints.tryParse(stringBuilder.toString());
// Should never fail
if (version == null) {
throw new IllegalArgumentException("Could not retrieve server version!");
}
return version;
}
}