843 lines
28 KiB
Java
843 lines
28 KiB
Java
package world.bentobox.bentobox.api.user;
|
|
|
|
import java.util.Collections;
|
|
import java.util.EnumMap;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Locale;
|
|
import java.util.Map;
|
|
import java.util.Objects;
|
|
import java.util.Optional;
|
|
import java.util.Set;
|
|
import java.util.UUID;
|
|
|
|
import org.apache.commons.lang.math.NumberUtils;
|
|
import org.bukkit.Bukkit;
|
|
import org.bukkit.ChatColor;
|
|
import org.bukkit.GameMode;
|
|
import org.bukkit.Location;
|
|
import org.bukkit.OfflinePlayer;
|
|
import org.bukkit.Particle;
|
|
import org.bukkit.Particle.DustTransition;
|
|
import org.bukkit.Vibration;
|
|
import org.bukkit.World;
|
|
import org.bukkit.block.data.BlockData;
|
|
import org.bukkit.command.CommandSender;
|
|
import org.bukkit.entity.Player;
|
|
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
|
import org.bukkit.inventory.ItemStack;
|
|
import org.bukkit.inventory.PlayerInventory;
|
|
import org.bukkit.permissions.PermissionAttachment;
|
|
import org.bukkit.permissions.PermissionAttachmentInfo;
|
|
import org.bukkit.util.Vector;
|
|
import org.eclipse.jdt.annotation.NonNull;
|
|
import org.eclipse.jdt.annotation.Nullable;
|
|
|
|
import world.bentobox.bentobox.BentoBox;
|
|
import world.bentobox.bentobox.api.addons.Addon;
|
|
import world.bentobox.bentobox.api.events.OfflineMessageEvent;
|
|
import world.bentobox.bentobox.api.metadata.MetaDataAble;
|
|
import world.bentobox.bentobox.api.metadata.MetaDataValue;
|
|
import world.bentobox.bentobox.database.objects.Players;
|
|
import world.bentobox.bentobox.util.Util;
|
|
|
|
/**
|
|
* Combines {@link Player}, {@link OfflinePlayer} and {@link CommandSender} to
|
|
* provide convenience methods related to localization and generic interactions.
|
|
* <br/>
|
|
* Therefore, a User could usually be a Player, an OfflinePlayer or the server's
|
|
* console. Preliminary checks should be performed before trying to run methods
|
|
* that relies on a specific implementation. <br/>
|
|
* <br/>
|
|
* It is good practice to use the User instance whenever possible instead of
|
|
* Player or CommandSender.
|
|
*
|
|
* @author tastybento
|
|
*/
|
|
public class User implements MetaDataAble {
|
|
|
|
private static final Map<UUID, User> users = new HashMap<>();
|
|
|
|
// Used for particle validation
|
|
private static final Map<Particle, Class<?>> VALIDATION_CHECK;
|
|
static {
|
|
Map<Particle, Class<?>> v = new EnumMap<>(Particle.class);
|
|
v.put(Particle.REDSTONE, Particle.DustOptions.class);
|
|
v.put(Particle.ITEM_CRACK, ItemStack.class);
|
|
v.put(Particle.BLOCK_CRACK, BlockData.class);
|
|
v.put(Particle.BLOCK_DUST, BlockData.class);
|
|
v.put(Particle.FALLING_DUST, BlockData.class);
|
|
v.put(Particle.BLOCK_MARKER, BlockData.class);
|
|
v.put(Particle.DUST_COLOR_TRANSITION, DustTransition.class);
|
|
v.put(Particle.VIBRATION, Vibration.class);
|
|
v.put(Particle.SCULK_CHARGE, Float.class);
|
|
v.put(Particle.SHRIEK, Integer.class);
|
|
v.put(Particle.LEGACY_BLOCK_CRACK, BlockData.class);
|
|
v.put(Particle.LEGACY_BLOCK_DUST, BlockData.class);
|
|
v.put(Particle.LEGACY_FALLING_DUST, BlockData.class);
|
|
VALIDATION_CHECK = Collections.unmodifiableMap(v);
|
|
}
|
|
|
|
/**
|
|
* Clears all users from the user list
|
|
*/
|
|
public static void clearUsers() {
|
|
users.clear();
|
|
}
|
|
|
|
/**
|
|
* Gets an instance of User from a CommandSender
|
|
*
|
|
* @param sender - command sender, e.g. console
|
|
* @return user - user
|
|
*/
|
|
@NonNull
|
|
public static User getInstance(@NonNull CommandSender sender) {
|
|
if (sender instanceof Player p) {
|
|
return getInstance(p);
|
|
}
|
|
// Console
|
|
return new User(sender);
|
|
}
|
|
|
|
/**
|
|
* Gets an instance of User from a Player object.
|
|
*
|
|
* @param player - the player
|
|
* @return user - user
|
|
*/
|
|
@NonNull
|
|
public static User getInstance(@NonNull Player player) {
|
|
if (users.containsKey(player.getUniqueId())) {
|
|
return users.get(player.getUniqueId());
|
|
}
|
|
return new User(player);
|
|
}
|
|
|
|
/**
|
|
* Gets an instance of User from a UUID. This will always return a user object.
|
|
* If the player is offline then the getPlayer value will be null.
|
|
*
|
|
* @param uuid - UUID
|
|
* @return user - user
|
|
*/
|
|
@NonNull
|
|
public static User getInstance(@NonNull UUID uuid) {
|
|
if (users.containsKey(uuid)) {
|
|
return users.get(uuid);
|
|
}
|
|
// Return a user instance
|
|
return new User(uuid);
|
|
}
|
|
|
|
/**
|
|
* Gets an instance of User from an OfflinePlayer
|
|
*
|
|
* @param offlinePlayer offline Player
|
|
* @return user
|
|
* @since 1.3.0
|
|
*/
|
|
@NonNull
|
|
public static User getInstance(@NonNull OfflinePlayer offlinePlayer) {
|
|
if (users.containsKey(offlinePlayer.getUniqueId())) {
|
|
return users.get(offlinePlayer.getUniqueId());
|
|
}
|
|
return new User(offlinePlayer);
|
|
}
|
|
|
|
/**
|
|
* Removes this player from the User cache and player manager cache
|
|
*
|
|
* @param player the player
|
|
*/
|
|
public static void removePlayer(Player player) {
|
|
if (player != null) {
|
|
users.remove(player.getUniqueId());
|
|
BentoBox.getInstance().getPlayers().removePlayer(player);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------
|
|
|
|
private static BentoBox plugin = BentoBox.getInstance();
|
|
|
|
@Nullable
|
|
private final Player player;
|
|
private OfflinePlayer offlinePlayer;
|
|
private final UUID playerUUID;
|
|
@Nullable
|
|
private final CommandSender sender;
|
|
|
|
private Addon addon;
|
|
|
|
private User(@Nullable CommandSender sender) {
|
|
player = null;
|
|
playerUUID = null;
|
|
this.sender = sender;
|
|
}
|
|
|
|
private User(@NonNull Player player) {
|
|
this.player = player;
|
|
offlinePlayer = player;
|
|
sender = player;
|
|
playerUUID = player.getUniqueId();
|
|
users.put(playerUUID, this);
|
|
}
|
|
|
|
private User(@NonNull OfflinePlayer offlinePlayer) {
|
|
this.player = offlinePlayer.isOnline() ? offlinePlayer.getPlayer() : null;
|
|
this.playerUUID = offlinePlayer.getUniqueId();
|
|
this.sender = offlinePlayer.isOnline() ? offlinePlayer.getPlayer() : null;
|
|
this.offlinePlayer = offlinePlayer;
|
|
}
|
|
|
|
private User(UUID playerUUID) {
|
|
player = Bukkit.getPlayer(playerUUID);
|
|
this.playerUUID = playerUUID;
|
|
sender = player;
|
|
offlinePlayer = Bukkit.getOfflinePlayer(playerUUID);
|
|
}
|
|
|
|
/**
|
|
* Used for testing
|
|
*
|
|
* @param p - plugin
|
|
*/
|
|
public static void setPlugin(BentoBox p) {
|
|
plugin = p;
|
|
}
|
|
|
|
public Set<PermissionAttachmentInfo> getEffectivePermissions() {
|
|
return sender.getEffectivePermissions();
|
|
}
|
|
|
|
/**
|
|
* Get the user's inventory
|
|
*
|
|
* @return player's inventory
|
|
*/
|
|
@NonNull
|
|
public PlayerInventory getInventory() {
|
|
return Objects.requireNonNull(player, "getInventory can only be called for online players!").getInventory();
|
|
}
|
|
|
|
/**
|
|
* Get the user's location
|
|
*
|
|
* @return location
|
|
*/
|
|
@NonNull
|
|
public Location getLocation() {
|
|
return Objects.requireNonNull(player, "getLocation can only be called for online players!").getLocation();
|
|
}
|
|
|
|
/**
|
|
* Get the user's name
|
|
*
|
|
* @return player's name
|
|
*/
|
|
@NonNull
|
|
public String getName() {
|
|
return player != null ? player.getName() : plugin.getPlayers().getName(playerUUID);
|
|
}
|
|
|
|
/**
|
|
* Get the user's display name
|
|
*
|
|
* @return player's display name if the player is online otherwise just their
|
|
* name
|
|
* @since 1.22.1
|
|
*/
|
|
@NonNull
|
|
public String getDisplayName() {
|
|
return player != null ? player.getDisplayName() : plugin.getPlayers().getName(playerUUID);
|
|
}
|
|
|
|
/**
|
|
* Check if the User is a player before calling this method. {@link #isPlayer()}
|
|
*
|
|
* @return the player
|
|
*/
|
|
@NonNull
|
|
public Player getPlayer() {
|
|
return Objects.requireNonNull(player, "User is not a player!");
|
|
}
|
|
|
|
/**
|
|
* @return true if this user is a player, false if not, e.g., console
|
|
*/
|
|
public boolean isPlayer() {
|
|
return player != null;
|
|
}
|
|
|
|
/**
|
|
* Use {@link #isOfflinePlayer()} before calling this method
|
|
*
|
|
* @return the offline player
|
|
* @since 1.3.0
|
|
*/
|
|
@NonNull
|
|
public OfflinePlayer getOfflinePlayer() {
|
|
return Objects.requireNonNull(offlinePlayer, "User is not an OfflinePlayer!");
|
|
}
|
|
|
|
/**
|
|
* @return true if this user is an OfflinePlayer, false if not, e.g., console
|
|
* @since 1.3.0
|
|
*/
|
|
public boolean isOfflinePlayer() {
|
|
return offlinePlayer != null;
|
|
}
|
|
|
|
@Nullable
|
|
public CommandSender getSender() {
|
|
return sender;
|
|
}
|
|
|
|
public UUID getUniqueId() {
|
|
return playerUUID;
|
|
}
|
|
|
|
/**
|
|
* @param permission permission string
|
|
* @return true if permission is empty or null or if the player has that
|
|
* permission or if the player is op.
|
|
*/
|
|
public boolean hasPermission(@Nullable String permission) {
|
|
return permission == null || permission.isEmpty() || isOp() || sender.hasPermission(permission);
|
|
}
|
|
|
|
/**
|
|
* Removes permission from user
|
|
*
|
|
* @param name - Name of the permission to remove
|
|
* @return true if successful
|
|
* @since 1.5.0
|
|
*/
|
|
public boolean removePerm(String name) {
|
|
for (PermissionAttachmentInfo p : player.getEffectivePermissions()) {
|
|
if (p.getPermission().equals(name) && p.getAttachment() != null) {
|
|
player.removeAttachment(p.getAttachment());
|
|
break;
|
|
}
|
|
}
|
|
player.recalculatePermissions();
|
|
return !player.hasPermission(name);
|
|
}
|
|
|
|
/**
|
|
* Add a permission to user
|
|
*
|
|
* @param name - Name of the permission to attach
|
|
* @return The PermissionAttachment that was just created
|
|
* @since 1.5.0
|
|
*/
|
|
public PermissionAttachment addPerm(String name) {
|
|
return player.addAttachment(plugin, name, true);
|
|
}
|
|
|
|
public boolean isOnline() {
|
|
return player != null && player.isOnline();
|
|
}
|
|
|
|
/**
|
|
* Checks if user is Op
|
|
*
|
|
* @return true if user is Op
|
|
*/
|
|
public boolean isOp() {
|
|
if (sender != null) {
|
|
return sender.isOp();
|
|
}
|
|
if (playerUUID != null && offlinePlayer != null) {
|
|
return offlinePlayer.isOp();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Get the maximum value of a numerical permission setting. If a player is given
|
|
* an explicit negative number then this is treated as "unlimited" and returned
|
|
* immediately.
|
|
*
|
|
* @param permissionPrefix the start of the perm, e.g.,
|
|
* {@code plugin.mypermission}
|
|
* @param defaultValue the default value; the result may be higher or lower
|
|
* than this
|
|
* @return max value
|
|
*/
|
|
public int getPermissionValue(String permissionPrefix, int defaultValue) {
|
|
// If requester is console, then return the default value
|
|
if (!isPlayer())
|
|
return defaultValue;
|
|
|
|
// If there is a dot at the end of the permissionPrefix, remove it
|
|
if (permissionPrefix.endsWith(".")) {
|
|
permissionPrefix = permissionPrefix.substring(0, permissionPrefix.length() - 1);
|
|
}
|
|
|
|
final String permPrefix = permissionPrefix + ".";
|
|
|
|
List<String> permissions = player.getEffectivePermissions().stream().filter(PermissionAttachmentInfo::getValue) // Must
|
|
// be
|
|
// a
|
|
// positive
|
|
// permission,
|
|
// not
|
|
// a
|
|
// negative
|
|
// one
|
|
.map(PermissionAttachmentInfo::getPermission).filter(permission -> permission.startsWith(permPrefix))
|
|
.toList();
|
|
|
|
if (permissions.isEmpty())
|
|
return defaultValue;
|
|
|
|
return iteratePerms(permissions, permPrefix, defaultValue);
|
|
|
|
}
|
|
|
|
private int iteratePerms(List<String> permissions, String permPrefix, int defaultValue) {
|
|
int value = 0;
|
|
for (String permission : permissions) {
|
|
if (permission.contains(permPrefix + "*")) {
|
|
// 'Star' permission
|
|
return defaultValue;
|
|
} else {
|
|
String[] spl = permission.split(permPrefix);
|
|
if (spl.length > 1) {
|
|
if (!NumberUtils.isNumber(spl[1])) {
|
|
plugin.logError("Player " + player.getName() + " has permission: '" + permission
|
|
+ "' <-- the last part MUST be a number! Ignoring...");
|
|
} else {
|
|
int v = Integer.parseInt(spl[1]);
|
|
if (v < 0) {
|
|
return v;
|
|
}
|
|
value = Math.max(value, v);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
/**
|
|
* Gets a translation for a specific world
|
|
*
|
|
* @param world - world of translation
|
|
* @param reference - reference found in a locale file
|
|
* @param variables - variables to insert into translated string. Variables go
|
|
* in pairs, for example "[name]", "tastybento"
|
|
* @return Translated string with colors converted, or the reference if nothing
|
|
* has been found
|
|
* @since 1.3.0
|
|
*/
|
|
public String getTranslation(World world, String reference, String... variables) {
|
|
// Get translation.
|
|
String addonPrefix = plugin.getIWM().getAddon(world)
|
|
.map(a -> a.getDescription().getName().toLowerCase(Locale.ENGLISH) + ".").orElse("");
|
|
return Util.translateColorCodes(translate(addonPrefix, reference, variables));
|
|
}
|
|
|
|
/**
|
|
* Gets a translation of this reference for this user with colors converted.
|
|
* Translations may be overridden by Addons by using the same reference prefixed
|
|
* by the addon name (from the Addon Description) in lower case.
|
|
*
|
|
* @param reference - reference found in a locale file
|
|
* @param variables - variables to insert into translated string. Variables go
|
|
* in pairs, for example "[name]", "tastybento"
|
|
* @return Translated string with colors converted, or the reference if nothing
|
|
* has been found
|
|
*/
|
|
public String getTranslation(String reference, String... variables) {
|
|
// Get addonPrefix
|
|
String addonPrefix = addon == null ? "" : addon.getDescription().getName().toLowerCase(Locale.ENGLISH) + ".";
|
|
return Util.translateColorCodes(translate(addonPrefix, reference, variables));
|
|
}
|
|
|
|
/**
|
|
* Gets a translation of this reference for this user without colors translated.
|
|
* Translations may be overridden by Addons by using the same reference prefixed
|
|
* by the addon name (from the Addon Description) in lower case.
|
|
*
|
|
* @param reference - reference found in a locale file
|
|
* @param variables - variables to insert into translated string. Variables go
|
|
* in pairs, for example "[name]", "tastybento"
|
|
* @return Translated string or the reference if nothing has been found
|
|
* @since 1.17.4
|
|
*/
|
|
public String getTranslationNoColor(String reference, String... variables) {
|
|
// Get addonPrefix
|
|
String addonPrefix = addon == null ? "" : addon.getDescription().getName().toLowerCase(Locale.ENGLISH) + ".";
|
|
return translate(addonPrefix, reference, variables);
|
|
}
|
|
|
|
private String translate(String addonPrefix, String reference, String[] variables) {
|
|
// Try to get the translation for this specific addon
|
|
String translation = plugin.getLocalesManager().get(this, addonPrefix + reference);
|
|
|
|
if (translation == null) {
|
|
// No luck, try to get the generic translation
|
|
translation = plugin.getLocalesManager().get(this, reference);
|
|
if (translation == null) {
|
|
// Nothing found. Replace vars (probably will do nothing) and return
|
|
return replaceVars(reference, variables);
|
|
}
|
|
}
|
|
|
|
// If this is a prefix, just gather and return the translation
|
|
if (!reference.startsWith("prefixes.")) {
|
|
// Replace the prefixes
|
|
return replacePrefixes(translation, variables);
|
|
}
|
|
return translation;
|
|
}
|
|
|
|
private String replacePrefixes(String translation, String[] variables) {
|
|
for (String prefix : plugin.getLocalesManager().getAvailablePrefixes(this)) {
|
|
String prefixTranslation = getTranslation("prefixes." + prefix);
|
|
// Replace the [gamemode] text variable
|
|
prefixTranslation = prefixTranslation.replace("[gamemode]",
|
|
addon != null ? addon.getDescription().getName() : "[gamemode]");
|
|
// Replace the [friendly_name] text variable
|
|
prefixTranslation = prefixTranslation.replace("[friendly_name]",
|
|
isPlayer() ? plugin.getIWM().getFriendlyName(getWorld()) : "[friendly_name]");
|
|
|
|
// Replace the prefix in the actual message
|
|
translation = translation.replace("[prefix_" + prefix + "]", prefixTranslation);
|
|
}
|
|
|
|
// Then replace variables
|
|
if (variables.length > 1) {
|
|
for (int i = 0; i < variables.length; i += 2) {
|
|
// Prevent a NPE if the substituting variable is null
|
|
if (variables[i + 1] != null) {
|
|
translation = translation.replace(variables[i], variables[i + 1]);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Then replace Placeholders, this will only work if this is a player
|
|
if (player != null) {
|
|
translation = plugin.getPlaceholdersManager().replacePlaceholders(player, translation);
|
|
}
|
|
return translation;
|
|
}
|
|
|
|
private String replaceVars(String reference, String[] variables) {
|
|
|
|
// Then replace variables
|
|
if (variables.length > 1) {
|
|
for (int i = 0; i < variables.length; i += 2) {
|
|
reference = reference.replace(variables[i], variables[i + 1]);
|
|
}
|
|
}
|
|
|
|
// Then replace Placeholders, this will only work if this is a player
|
|
if (player != null) {
|
|
reference = plugin.getPlaceholdersManager().replacePlaceholders(player, reference);
|
|
}
|
|
|
|
// If no translation has been found, return the reference for debug purposes.
|
|
return reference;
|
|
}
|
|
|
|
/**
|
|
* Gets a translation of this reference for this user.
|
|
*
|
|
* @param reference - reference found in a locale file
|
|
* @param variables - variables to insert into translated string. Variables go
|
|
* in pairs, for example "[name]", "tastybento"
|
|
* @return Translated string with colors converted, or a blank String if nothing
|
|
* has been found
|
|
*/
|
|
public String getTranslationOrNothing(String reference, String... variables) {
|
|
String translation = getTranslation(reference, variables);
|
|
return translation.equals(reference) ? "" : translation;
|
|
}
|
|
|
|
/**
|
|
* Send a message to sender if message is not empty.
|
|
*
|
|
* @param reference - language file reference
|
|
* @param variables - CharSequence target, replacement pairs
|
|
*/
|
|
public void sendMessage(String reference, String... variables) {
|
|
String message = getTranslation(reference, variables);
|
|
if (!ChatColor.stripColor(message).trim().isEmpty()) {
|
|
sendRawMessage(message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sends a message to sender without any modification (colors, multi-lines,
|
|
* placeholders).
|
|
*
|
|
* @param message - the message to send
|
|
*/
|
|
public void sendRawMessage(String message) {
|
|
if (sender != null) {
|
|
sender.sendMessage(message);
|
|
} else {
|
|
// Offline player fire event
|
|
Bukkit.getPluginManager().callEvent(new OfflineMessageEvent(this.playerUUID, message));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sends a message to sender if message is not empty and if the same wasn't sent
|
|
* within the previous Notifier.NOTIFICATION_DELAY seconds.
|
|
*
|
|
* @param reference - language file reference
|
|
* @param variables - CharSequence target, replacement pairs
|
|
*
|
|
* @see Notifier
|
|
*/
|
|
public void notify(String reference, String... variables) {
|
|
String message = getTranslation(reference, variables);
|
|
if (!ChatColor.stripColor(message).trim().isEmpty() && sender != null) {
|
|
plugin.getNotifier().notify(this, message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sends a message to sender if message is not empty and if the same wasn't sent
|
|
* within the previous Notifier.NOTIFICATION_DELAY seconds.
|
|
*
|
|
* @param world - the world the translation should come from
|
|
* @param reference - language file reference
|
|
* @param variables - CharSequence target, replacement pairs
|
|
*
|
|
* @see Notifier
|
|
* @since 1.3.0
|
|
*/
|
|
public void notify(World world, String reference, String... variables) {
|
|
String message = getTranslation(world, reference, variables);
|
|
if (!ChatColor.stripColor(message).trim().isEmpty() && sender != null) {
|
|
plugin.getNotifier().notify(this, message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets the user's game mode
|
|
*
|
|
* @param mode - GameMode
|
|
*/
|
|
public void setGameMode(GameMode mode) {
|
|
player.setGameMode(mode);
|
|
}
|
|
|
|
/**
|
|
* Teleports user to this location. If the user is in a vehicle, they will exit
|
|
* first.
|
|
*
|
|
* @param location - the location
|
|
*/
|
|
public void teleport(Location location) {
|
|
player.teleport(location);
|
|
}
|
|
|
|
/**
|
|
* Gets the current world this entity resides in
|
|
*
|
|
* @return World - world
|
|
*/
|
|
@NonNull
|
|
public World getWorld() {
|
|
Objects.requireNonNull(player, "Cannot be called on a non-player User!");
|
|
return Objects.requireNonNull(player.getWorld(), "Player's world cannot be null!");
|
|
}
|
|
|
|
/**
|
|
* Closes the user's inventory
|
|
*/
|
|
public void closeInventory() {
|
|
player.closeInventory();
|
|
}
|
|
|
|
/**
|
|
* Get the user's locale
|
|
*
|
|
* @return Locale
|
|
*/
|
|
public Locale getLocale() {
|
|
if (sender instanceof Player && !plugin.getPlayers().getLocale(playerUUID).isEmpty()) {
|
|
return Locale.forLanguageTag(plugin.getPlayers().getLocale(playerUUID));
|
|
}
|
|
return Locale.forLanguageTag(plugin.getSettings().getDefaultLanguage());
|
|
}
|
|
|
|
/**
|
|
* Forces an update of the user's complete inventory. Deprecated, but there is
|
|
* no current alternative.
|
|
*/
|
|
public void updateInventory() {
|
|
player.updateInventory();
|
|
}
|
|
|
|
/**
|
|
* Performs a command as the player
|
|
*
|
|
* @param command - command to execute
|
|
* @return true if the command was successful, otherwise false
|
|
*/
|
|
public boolean performCommand(String command) {
|
|
PlayerCommandPreprocessEvent event = new PlayerCommandPreprocessEvent(getPlayer(), command);
|
|
Bukkit.getPluginManager().callEvent(event);
|
|
|
|
// only perform the command, if the event wasn't cancelled by an other plugin:
|
|
if (!event.isCancelled()) {
|
|
return getPlayer().performCommand(
|
|
event.getMessage().startsWith("/") ? event.getMessage().substring(1) : event.getMessage());
|
|
}
|
|
// Cancelled, but it was recognized, so return true
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Checks if a user is in one of the game worlds
|
|
*
|
|
* @return true if user is, false if not
|
|
*/
|
|
public boolean inWorld() {
|
|
return plugin.getIWM().inWorld(getLocation());
|
|
}
|
|
|
|
/**
|
|
* Spawn particles to the player. They are only displayed if they are within the
|
|
* server's view distance.
|
|
*
|
|
* @param particle Particle to display.
|
|
* @param dustOptions Particle.DustOptions for the particle to display. Cannot
|
|
* be null when particle is {@link Particle#REDSTONE}.
|
|
* @param x X coordinate of the particle to display.
|
|
* @param y Y coordinate of the particle to display.
|
|
* @param z Z coordinate of the particle to display.
|
|
*/
|
|
public void spawnParticle(Particle particle, @Nullable Object dustOptions, double x, double y, double z) {
|
|
Class<?> expectedClass = VALIDATION_CHECK.get(particle);
|
|
if (expectedClass == null)
|
|
throw new IllegalArgumentException("Unexpected value: " + particle);
|
|
|
|
if (!(expectedClass.isInstance(dustOptions))) {
|
|
throw new IllegalArgumentException("A non-null " + expectedClass.getSimpleName()
|
|
+ " must be provided when using Particle." + particle + " as particle.");
|
|
}
|
|
|
|
// Check if this particle is beyond the viewing distance of the server
|
|
if (this.player != null && this.player.getLocation().toVector().distanceSquared(new Vector(x, y,
|
|
z)) < (Bukkit.getServer().getViewDistance() * 256 * Bukkit.getServer().getViewDistance())) {
|
|
if (particle.equals(Particle.REDSTONE)) {
|
|
player.spawnParticle(particle, x, y, z, 1, 0, 0, 0, 1, dustOptions);
|
|
} else if (dustOptions != null) {
|
|
player.spawnParticle(particle, x, y, z, 1, dustOptions);
|
|
} else {
|
|
// This will never be called unless the value in VALIDATION_CHECK is null in the
|
|
// future
|
|
player.spawnParticle(particle, x, y, z, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Spawn particles to the player. They are only displayed if they are within the
|
|
* server's view distance. Compatibility method for older usages.
|
|
*
|
|
* @param particle Particle to display.
|
|
* @param dustOptions Particle.DustOptions for the particle to display. Cannot
|
|
* be null when particle is {@link Particle#REDSTONE}.
|
|
* @param x X coordinate of the particle to display.
|
|
* @param y Y coordinate of the particle to display.
|
|
* @param z Z coordinate of the particle to display.
|
|
*/
|
|
public void spawnParticle(Particle particle, Particle.DustOptions dustOptions, double x, double y, double z) {
|
|
this.spawnParticle(particle, (Object) dustOptions, x, y, z);
|
|
}
|
|
|
|
/**
|
|
* Spawn particles to the player. They are only displayed if they are within the
|
|
* server's view distance.
|
|
*
|
|
* @param particle Particle to display.
|
|
* @param dustOptions Particle.DustOptions for the particle to display. Cannot
|
|
* be null when particle is {@link Particle#REDSTONE}.
|
|
* @param x X coordinate of the particle to display.
|
|
* @param y Y coordinate of the particle to display.
|
|
* @param z Z coordinate of the particle to display.
|
|
*/
|
|
public void spawnParticle(Particle particle, Particle.DustOptions dustOptions, int x, int y, int z) {
|
|
this.spawnParticle(particle, dustOptions, (double) x, (double) y, (double) z);
|
|
}
|
|
|
|
/*
|
|
* (non-Javadoc)
|
|
*
|
|
* @see java.lang.Object#hashCode()
|
|
*/
|
|
@Override
|
|
public int hashCode() {
|
|
final int prime = 31;
|
|
int result = 1;
|
|
result = prime * result + ((playerUUID == null) ? 0 : playerUUID.hashCode());
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* (non-Javadoc)
|
|
*
|
|
* @see java.lang.Object#equals(java.lang.Object)
|
|
*/
|
|
@Override
|
|
public boolean equals(Object obj) {
|
|
if (this == obj) {
|
|
return true;
|
|
}
|
|
if (obj == null) {
|
|
return false;
|
|
}
|
|
if (!(obj instanceof User other)) {
|
|
return false;
|
|
}
|
|
if (playerUUID == null) {
|
|
return other.playerUUID == null;
|
|
} else
|
|
return playerUUID.equals(other.playerUUID);
|
|
}
|
|
|
|
/**
|
|
* Set the addon context when a command is executed
|
|
*
|
|
* @param addon - the addon executing the command
|
|
*/
|
|
public void setAddon(Addon addon) {
|
|
this.addon = addon;
|
|
}
|
|
|
|
/**
|
|
* Get all the meta data for this user
|
|
*
|
|
* @return the metaData
|
|
* @since 1.15.4
|
|
*/
|
|
@Override
|
|
public Optional<Map<String, MetaDataValue>> getMetaData() {
|
|
Players p = plugin.getPlayers().getPlayer(playerUUID);
|
|
return Objects.requireNonNull(p, "Unknown player for " + playerUUID).getMetaData();
|
|
}
|
|
|
|
/**
|
|
* @param metaData the metaData to set
|
|
* @since 1.15.4
|
|
*/
|
|
@Override
|
|
public void setMetaData(Map<String, MetaDataValue> metaData) {
|
|
Players p = plugin.getPlayers().getPlayer(playerUUID);
|
|
|
|
Objects.requireNonNull(p, "Unknown player for " + playerUUID).setMetaData(metaData);
|
|
}
|
|
|
|
}
|