package net.aufdemrand.denizen.objects; import net.aufdemrand.denizen.flags.FlagManager; import net.aufdemrand.denizen.nms.NMSHandler; import net.aufdemrand.denizen.nms.NMSVersion; import net.aufdemrand.denizen.nms.abstracts.ImprovedOfflinePlayer; import net.aufdemrand.denizen.nms.abstracts.Sidebar; import net.aufdemrand.denizen.objects.properties.entity.EntityHealth; import net.aufdemrand.denizen.scripts.commands.core.FailCommand; import net.aufdemrand.denizen.scripts.commands.core.FinishCommand; import net.aufdemrand.denizen.scripts.commands.player.SidebarCommand; import net.aufdemrand.denizen.tags.core.PlayerTags; import net.aufdemrand.denizen.utilities.DenizenAPI; import net.aufdemrand.denizen.utilities.debugging.dB; import net.aufdemrand.denizen.utilities.depends.Depends; import net.aufdemrand.denizen.utilities.packets.ItemChangeMessage; import net.aufdemrand.denizencore.objects.*; import net.aufdemrand.denizencore.objects.properties.Property; import net.aufdemrand.denizencore.objects.properties.PropertyParser; import net.aufdemrand.denizencore.tags.Attribute; import net.aufdemrand.denizencore.tags.TagContext; import net.aufdemrand.denizencore.utilities.CoreUtilities; import net.citizensnpcs.api.CitizensAPI; import net.citizensnpcs.api.npc.NPC; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.block.banner.PatternType; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.CraftingInventory; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.PlayerInventory; import org.bukkit.map.MapView; import org.bukkit.potion.PotionEffect; import org.bukkit.util.BlockIterator; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.regex.Pattern; public class dPlayer implements dObject, Adjustable { ///////////////////// // STATIC METHODS ///////////////// public static dPlayer mirrorBukkitPlayer(OfflinePlayer player) { if (player == null) { return null; } else { return new dPlayer(player); } } static Map<String, UUID> playerNames = new HashMap<String, UUID>(); /** * Notes that the player exists, for easy dPlayer valueOf handling. */ public static void notePlayer(OfflinePlayer player) { if (player.getName() == null) { dB.echoError("Null player " + player.toString()); return; } if (!playerNames.containsKey(CoreUtilities.toLowerCase(player.getName()))) { playerNames.put(CoreUtilities.toLowerCase(player.getName()), player.getUniqueId()); } } public static boolean isNoted(OfflinePlayer player) { return playerNames.containsValue(player.getUniqueId()); } public static Map<String, UUID> getAllPlayers() { return playerNames; } ///////////////////// // OBJECT FETCHER ///////////////// // <--[language] // @name p@ // @group Object Fetcher System // @description // p@ refers to the 'object identifier' of a dPlayer. The 'p@' is notation for Denizen's Object // Fetcher. The only valid constructor for a dPlayer is the name of the player the object should be // associated with. For example, to reference the player named 'mythan', use p@mythan. Player names // are case insensitive. // --> public static dPlayer valueOf(String string) { return valueOf(string, null); } @Fetchable("p") public static dPlayer valueOf(String string, TagContext context) { return valueOfInternal(string, context == null || context.debug); } static dPlayer valueOfInternal(String string, boolean announce) { if (string == null) { return null; } string = string.replace("p@", "").replace("P@", ""); // Match as a UUID if (string.indexOf('-') >= 0) { try { UUID uuid = UUID.fromString(string); if (uuid != null) { OfflinePlayer player = Bukkit.getOfflinePlayer(uuid); if (player != null) { return new dPlayer(player); } } } catch (IllegalArgumentException e) { // Nothing } } // Match as a player name if (playerNames.containsKey(CoreUtilities.toLowerCase(string))) { OfflinePlayer player = Bukkit.getOfflinePlayer(playerNames.get(CoreUtilities.toLowerCase(string))); return new dPlayer(player); } if (announce) { dB.log("Minor: Invalid Player! '" + string + "' could not be found."); } return null; } public static boolean matches(String arg) { // If passed null, of course it doesn't match! if (arg == null) { return false; } // If passed a identified object that starts with 'p@', return true // even if the player doesn't technically exist. if (CoreUtilities.toLowerCase(arg).startsWith("p@")) { return true; } arg = arg.replace("p@", "").replace("P@", ""); if (arg.indexOf('-') >= 0) { try { UUID uuid = UUID.fromString(arg); if (uuid != null) { OfflinePlayer player = Bukkit.getOfflinePlayer(uuid); if (player != null && player.hasPlayedBefore()) { return true; } } } catch (IllegalArgumentException e) { // Nothing } } return false; } public static boolean playerNameIsValid(String name) { return playerNames.containsKey(CoreUtilities.toLowerCase(name)); } ///////////////////// // CONSTRUCTORS ///////////////// public dPlayer(OfflinePlayer player) { offlinePlayer = player; } public dPlayer(UUID uuid) { offlinePlayer = Bukkit.getOfflinePlayer(uuid); } public dPlayer(Player player) { this((OfflinePlayer) player); if (dEntity.isNPC(player)) { throw new IllegalStateException("NPCs are not allowed as dPlayer objects!"); } } ///////////////////// // INSTANCE FIELDS/METHODS ///////////////// OfflinePlayer offlinePlayer = null; public boolean isValid() { return getPlayerEntity() != null || getOfflinePlayer() != null; } public Player getPlayerEntity() { if (offlinePlayer == null) { return null; } return Bukkit.getPlayer(offlinePlayer.getUniqueId()); } public OfflinePlayer getOfflinePlayer() { return offlinePlayer; } public ImprovedOfflinePlayer getNBTEditor() { return NMSHandler.getInstance().getPlayerHelper().getOfflineData(getOfflinePlayer()); } public dEntity getDenizenEntity() { return new dEntity(getPlayerEntity()); } public dNPC getSelectedNPC() { if (Depends.citizens != null) { NPC npc = CitizensAPI.getDefaultNPCSelector().getSelected(getPlayerEntity()); if (npc != null) { return dNPC.mirrorCitizensNPC(npc); } } return null; } public String getName() { if (offlinePlayer == null) { return null; } return offlinePlayer.getName(); } public String getSaveName() { if (offlinePlayer == null) { return "00.UNKNOWN"; } String baseID = offlinePlayer.getUniqueId().toString().toUpperCase().replace("-", ""); return baseID.substring(0, 2) + "." + baseID; } public dLocation getLocation() { if (isOnline()) { return new dLocation(getPlayerEntity().getLocation()); } else { return new dLocation(getNBTEditor().getLocation()); } } public int getRemainingAir() { if (isOnline()) { return getPlayerEntity().getRemainingAir(); } else { return getNBTEditor().getRemainingAir(); } } public int getMaximumAir() { if (isOnline()) { return getPlayerEntity().getMaximumAir(); } else { return 300; } } public double getHealth() { if (isOnline()) { return getPlayerEntity().getHealth(); } else { return getNBTEditor().getHealthFloat(); } } public double getMaxHealth() { if (isOnline()) { return getPlayerEntity().getMaxHealth(); } else { return getNBTEditor().getMaxHealth(); } } public int getFoodLevel() { if (isOnline()) { return getPlayerEntity().getFoodLevel(); } else { return getNBTEditor().getFoodLevel(); } } public dLocation getEyeLocation() { if (isOnline()) { return new dLocation(getPlayerEntity().getEyeLocation()); } else { return null; } } public PlayerInventory getBukkitInventory() { if (isOnline()) { return getPlayerEntity().getInventory(); } else { return getNBTEditor().getInventory(); } } public dInventory getInventory() { if (isOnline()) { return new dInventory(getPlayerEntity().getInventory()); } else { return new dInventory(getNBTEditor()); } } public CraftingInventory getBukkitWorkbench() { if (isOnline()) { if (getPlayerEntity().getOpenInventory().getType() == InventoryType.WORKBENCH || getPlayerEntity().getOpenInventory().getType() == InventoryType.CRAFTING) { return (CraftingInventory) getPlayerEntity().getOpenInventory().getTopInventory(); } } return null; } public dInventory getWorkbench() { if (isOnline()) { CraftingInventory workbench = getBukkitWorkbench(); if (workbench != null) { return new dInventory(workbench, getPlayerEntity()); } } return null; } public Inventory getBukkitEnderChest() { if (isOnline()) { return getPlayerEntity().getEnderChest(); } else { return getNBTEditor().getEnderChest(); } } public dInventory getEnderChest() { if (isOnline()) { return new dInventory(getPlayerEntity().getEnderChest(), getPlayerEntity()); } else { return new dInventory(getNBTEditor(), true); } } public World getWorld() { if (isOnline()) { return getPlayerEntity().getWorld(); } else { return null; } } public void decrementStatistic(Statistic statistic, int amount) { if (isOnline()) { getPlayerEntity().decrementStatistic(statistic, amount); } else { }// TODO: write to JSON? } public void decrementStatistic(Statistic statistic, EntityType entity, int amount) { if (isOnline() && statistic.getType() == Statistic.Type.ENTITY) { getPlayerEntity().decrementStatistic(statistic, entity, amount); } else { }// TODO: write to JSON? } public void decrementStatistic(Statistic statistic, Material material, int amount) { if (isOnline() && (statistic.getType() == Statistic.Type.BLOCK || statistic.getType() == Statistic.Type.ITEM)) { getPlayerEntity().decrementStatistic(statistic, material, amount); } else { }// TODO: write to JSON? } public void incrementStatistic(Statistic statistic, int amount) { if (isOnline()) { getPlayerEntity().incrementStatistic(statistic, amount); } else { }// TODO: write to JSON? } public void incrementStatistic(Statistic statistic, EntityType entity, int amount) { if (isOnline() && statistic.getType() == Statistic.Type.ENTITY) { getPlayerEntity().incrementStatistic(statistic, entity, amount); } else { }// TODO: write to JSON? } public void incrementStatistic(Statistic statistic, Material material, int amount) { if (isOnline() && (statistic.getType() == Statistic.Type.BLOCK || statistic.getType() == Statistic.Type.ITEM)) { getPlayerEntity().incrementStatistic(statistic, material, amount); } else { }// TODO: write to JSON? } public void setStatistic(Statistic statistic, int amount) { if (isOnline()) { getPlayerEntity().setStatistic(statistic, amount); } else { }// TODO: write to JSON? } public void setStatistic(Statistic statistic, EntityType entity, int amount) { if (isOnline() && statistic.getType() == Statistic.Type.ENTITY) { getPlayerEntity().setStatistic(statistic, entity, amount); } else { }// TODO: write to JSON? } public void setStatistic(Statistic statistic, Material material, int amount) { if (isOnline() && (statistic.getType() == Statistic.Type.BLOCK || statistic.getType() == Statistic.Type.ITEM)) { getPlayerEntity().setStatistic(statistic, material, amount); } else { }// TODO: write to JSON? } public boolean isOnline() { return getPlayerEntity() != null; } public void setBedSpawnLocation(Location location) { if (isOnline()) { getPlayerEntity().setBedSpawnLocation(location); } else { getNBTEditor().setBedSpawnLocation(location, getNBTEditor().isSpawnForced()); } } public void setLocation(Location location) { if (isOnline()) { getPlayerEntity().teleport(location); } else { getNBTEditor().setLocation(location); } } public void setMaximumAir(int air) { if (isOnline()) { getPlayerEntity().setMaximumAir(air); } else { dB.echoError("Cannot set the maximum air of an offline player!"); } } public void setRemainingAir(int air) { if (isOnline()) { getPlayerEntity().setRemainingAir(air); } else { getNBTEditor().setRemainingAir(air); } } public void setHealth(double health) { if (isOnline()) { getPlayerEntity().setHealth(health); } else { getNBTEditor().setHealthFloat((float) health); } } public void setMaxHealth(double maxHealth) { if (isOnline()) { getPlayerEntity().setMaxHealth(maxHealth); } else { getNBTEditor().setMaxHealth(maxHealth); } } public void setFoodLevel(int foodLevel) { if (isOnline()) { getPlayerEntity().setFoodLevel(foodLevel); } else { getNBTEditor().setFoodLevel(foodLevel); } } public void setLevel(int level) { if (isOnline()) { getPlayerEntity().setLevel(level); } else { getNBTEditor().setLevel(level); } } public void setFlySpeed(float speed) { if (isOnline()) { getPlayerEntity().setFlySpeed(speed); } else { getNBTEditor().setFlySpeed(speed); } } public void setGameMode(GameMode mode) { if (isOnline()) { getPlayerEntity().setGameMode(mode); } else { getNBTEditor().setGameMode(mode); } } public boolean hasChunkLoaded(Chunk chunk) { return NMSHandler.getInstance().getPlayerHelper().hasChunkLoaded(getPlayerEntity(), chunk); } ///////////////////// // dObject Methods ///////////////// private String prefix = "Player"; @Override public String getPrefix() { return prefix; } @Override public dPlayer setPrefix(String prefix) { this.prefix = prefix; return this; } @Override public String debug() { return (prefix + "='<A>" + identifySimple() + "<G>' "); } @Override public boolean isUnique() { return true; } @Override public String getObjectType() { return "Player"; } @Override public String identify() { return "p@" + offlinePlayer.getUniqueId().toString(); } @Override public String identifySimple() { return "p@" + offlinePlayer.getName(); } @Override public String toString() { return identify(); } @Override public String getAttribute(Attribute attribute) { if (attribute == null) { return null; } if (offlinePlayer == null) { return null; } ///////////////////// // OFFLINE ATTRIBUTES ///////////////// // Defined in dEntity if (attribute.startsWith("is_player")) { return Element.TRUE.getAttribute(attribute.fulfill(1)); } ///////////////////// // DEBUG ATTRIBUTES ///////////////// // <--[tag] // @attribute <p@player.debug.log> // @returns Element(Boolean) // @description // Debugs the player in the log and returns true. // Works with offline players. // --> if (attribute.startsWith("debug.log")) { dB.log(debug()); return Element.TRUE.getAttribute(attribute.fulfill(2)); } // <--[tag] // @attribute <p@player.debug.no_color> // @returns Element // @description // Returns the player's debug with no color. // Works with offline players. // --> if (attribute.startsWith("debug.no_color")) { return new Element(ChatColor.stripColor(debug())) .getAttribute(attribute.fulfill(2)); } // <--[tag] // @attribute <p@player.debug> // @returns Element // @description // Returns the player's debug. // Works with offline players. // --> if (attribute.startsWith("debug")) { return new Element(debug()) .getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.prefix> // @returns Element // @description // Returns the dObject's prefix. // Works with offline players. // --> if (attribute.startsWith("prefix")) { return new Element(prefix) .getAttribute(attribute.fulfill(1)); } ///////////////////// // DENIZEN ATTRIBUTES ///////////////// // <--[tag] // @attribute <p@player.chat_history_list> // @returns dList // @description // Returns a list of the last 10 things the player has said, less // if the player hasn't said all that much. // Works with offline players. // --> if (attribute.startsWith("chat_history_list")) { return new dList(PlayerTags.playerChatHistory.get(getName())) // TODO: UUID? .getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.chat_history[#]> // @returns Element // @description // Returns the last thing the player said. // If a number is specified, returns an earlier thing the player said. // Works with offline players. // --> if (attribute.startsWith("chat_history")) { int x = 1; if (attribute.hasContext(1) && aH.matchesInteger(attribute.getContext(1))) { x = attribute.getIntContext(1); } // No playerchathistory? Return null. if (!PlayerTags.playerChatHistory.containsKey(getName())) { // TODO: UUID? return null; } List<String> messages = PlayerTags.playerChatHistory.get(getName()); // TODO: UUID? if (messages.size() < x || x < 1) { return null; } return new Element(messages.get(x - 1)) .getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.flag[<flag_name>]> // @returns Flag dList // @description // Returns the specified flag from the player. // Works with offline players. // --> if (attribute.startsWith("flag") && attribute.hasContext(1)) { String flag_name = attribute.getContext(1); if (attribute.getAttribute(2).equalsIgnoreCase("is_expired") || attribute.startsWith("isexpired")) { return new Element(!FlagManager.playerHasFlag(this, flag_name)) .getAttribute(attribute.fulfill(2)); } if (attribute.getAttribute(2).equalsIgnoreCase("size") && !FlagManager.playerHasFlag(this, flag_name)) { return new Element(0).getAttribute(attribute.fulfill(2)); } if (FlagManager.playerHasFlag(this, flag_name)) { FlagManager.Flag flag = DenizenAPI.getCurrentInstance().flagManager() .getPlayerFlag(this, flag_name); return new dList(flag.toString(), true, flag.values()) .getAttribute(attribute.fulfill(1)); } return new Element(identify()).getAttribute(attribute); } // <--[tag] // @attribute <p@player.has_flag[<flag_name>]> // @returns Element(Boolean) // @description // Returns true if the Player has the specified flag, otherwise returns false. // Works with offline players. // --> if (attribute.startsWith("has_flag") && attribute.hasContext(1)) { String flag_name = attribute.getContext(1); return new Element(FlagManager.playerHasFlag(this, flag_name)).getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.list_flags[(regex:)<search>]> // @returns dList // @description // Returns a list of a player's flag names, with an optional search for // names containing a certain pattern. // Works with offline players. // --> if (attribute.startsWith("list_flags")) { dList allFlags = new dList(DenizenAPI.getCurrentInstance().flagManager().listPlayerFlags(this)); dList searchFlags = null; if (!allFlags.isEmpty() && attribute.hasContext(1)) { searchFlags = new dList(); String search = attribute.getContext(1); if (search.startsWith("regex:")) { try { Pattern pattern = Pattern.compile(search.substring(6), Pattern.CASE_INSENSITIVE); for (String flag : allFlags) { if (pattern.matcher(flag).matches()) { searchFlags.add(flag); } } } catch (Exception e) { dB.echoError(e); } } else { search = CoreUtilities.toLowerCase(search); for (String flag : allFlags) { if (CoreUtilities.toLowerCase(flag).contains(search)) { searchFlags.add(flag); } } } } return searchFlags == null ? allFlags.getAttribute(attribute.fulfill(1)) : searchFlags.getAttribute(attribute.fulfill(1)); } if (attribute.startsWith("current_step")) { String outcome = "null"; if (attribute.hasContext(1)) { try { outcome = DenizenAPI.getCurrentInstance().getSaves().getString("Players." + getName() + ".Scripts." + dScript.valueOf(attribute.getContext(1)).getName() + ".Current Step"); } catch (Exception e) { outcome = "null"; } } return new Element(outcome).getAttribute(attribute.fulfill(1)); } ///////////////////// // ECONOMY ATTRIBUTES ///////////////// // <--[tag] // @attribute <p@player.money> // @returns Element(Decimal) // @description // Returns the amount of money the player has with the registered Economy system. // May work offline depending on economy plugin. // @mechanism dPlayer.money // --> if (attribute.startsWith("money")) { if (Depends.economy != null) { // <--[tag] // @attribute <p@player.money.currency_singular> // @returns Element // @description // Returns the name of a single piece of currency - For example: Dollar // (Only if supported by the registered Economy system.) // --> if (attribute.startsWith("money.currency_singular")) { return new Element(Depends.economy.currencyNameSingular()) .getAttribute(attribute.fulfill(2)); } // <--[tag] // @attribute <p@player.money.currency> // @returns Element // @description // Returns the name of multiple pieces of currency - For example: Dollars // (Only if supported by the registered Economy system.) // --> if (attribute.startsWith("money.currency")) { return new Element(Depends.economy.currencyNamePlural()) .getAttribute(attribute.fulfill(2)); } return new Element(Depends.economy.getBalance(getOfflinePlayer())) .getAttribute(attribute.fulfill(1)); } else { if (!attribute.hasAlternative()) { dB.echoError("No economy loaded! Have you installed Vault and a compatible economy plugin?"); } return null; } } ///////////////////// // ENTITY LIST ATTRIBUTES ///////////////// // <--[tag] // @attribute <p@player.target[(<entity>|...)]> // @returns dEntity // @description // Returns the entity that the player is looking at, within a maximum range of 50 blocks, // or null if the player is not looking at an entity. // Optionally, specify a list of entities, entity types, or 'npc' to only count those targets. // --> if (attribute.startsWith("target")) { int range = 50; int attribs = 1; // <--[tag] // @attribute <p@player.target[(<entity>|...)].within[(<#>)]> // @returns dEntity // @description // Returns the entity that the player is looking at within the specified range limit, // or null if the player is not looking at an entity. // Optionally, specify a list of entities, entity types, or 'npc' to only count those targets. // --> if (attribute.getAttribute(2).startsWith("within") && attribute.hasContext(2) && aH.matchesInteger(attribute.getContext(2))) { attribs = 2; range = attribute.getIntContext(2); } List<Entity> entities = getPlayerEntity().getNearbyEntities(range, range, range); ArrayList<LivingEntity> possibleTargets = new ArrayList<LivingEntity>(); for (Entity entity : entities) { if (entity instanceof LivingEntity) { // if we have a context for entity types, check the entity if (attribute.hasContext(1)) { String context = attribute.getContext(1); if (CoreUtilities.toLowerCase(context).startsWith("li@")) { context = context.substring(3); } for (String ent : context.split("\\|")) { boolean valid = false; if (ent.equalsIgnoreCase("npc") && dEntity.isCitizensNPC(entity)) { valid = true; } else if (dEntity.matches(ent)) { // only accept generic entities that are not NPCs if (dEntity.valueOf(ent).isGeneric()) { if (dEntity.isCitizensNPC(entity)) { valid = true; } } else { valid = true; } } if (valid) { possibleTargets.add((LivingEntity) entity); } } } else { // no entity type specified possibleTargets.add((LivingEntity) entity); entity.getType(); } } } // Find the valid target BlockIterator bi; try { bi = new BlockIterator(getPlayerEntity(), range); } catch (IllegalStateException e) { return null; } Block b; Location l; int bx, by, bz; double ex, ey, ez; // Loop through player's line of sight while (bi.hasNext()) { b = bi.next(); bx = b.getX(); by = b.getY(); bz = b.getZ(); if (b.getType() != Material.AIR) { // Line of sight is broken break; } else { // Check for entities near this block in the line of sight for (LivingEntity possibleTarget : possibleTargets) { l = possibleTarget.getLocation(); ex = l.getX(); ey = l.getY(); ez = l.getZ(); if ((bx - .50 <= ex && ex <= bx + 1.50) && (bz - .50 <= ez && ez <= bz + 1.50) && (by - 1 <= ey && ey <= by + 2.5)) { // Entity is close enough, so return it return new dEntity(possibleTarget).getDenizenObject().getAttribute(attribute.fulfill(attribs)); } } } } return null; } // workaround for <e@entity.list_effects> if (attribute.startsWith("list_effects")) { dList effects = new dList(); for (PotionEffect effect : getPlayerEntity().getActivePotionEffects()) { effects.add(effect.getType().getName() + "," + effect.getAmplifier() + "," + effect.getDuration() + "t"); } return effects.getAttribute(attribute.fulfill(1)); } if (attribute.startsWith("list")) { dB.echoError("DO NOT USE PLAYER.LIST AS A TAG, please use <server.list_online_players> and related tags!"); List<String> players = new ArrayList<String>(); if (attribute.startsWith("list.online")) { for (Player player : Bukkit.getOnlinePlayers()) { players.add(player.getName()); } return new dList(players).getAttribute(attribute.fulfill(2)); } else if (attribute.startsWith("list.offline")) { for (OfflinePlayer player : Bukkit.getOfflinePlayers()) { if (!player.isOnline()) { players.add("p@" + player.getUniqueId().toString()); } } return new dList(players).getAttribute(attribute.fulfill(2)); } else { for (OfflinePlayer player : Bukkit.getOfflinePlayers()) { players.add("p@" + player.getUniqueId().toString()); } return new dList(players).getAttribute(attribute.fulfill(1)); } } ///////////////////// // IDENTIFICATION ATTRIBUTES ///////////////// if (attribute.startsWith("name") && !isOnline()) // This can be parsed later with more detail if the player is online, so only check for offline. { return new Element(getName()).getAttribute(attribute.fulfill(1)); } else if (attribute.startsWith("uuid") && !isOnline()) // This can be parsed later with more detail if the player is online, so only check for offline. { return new Element(offlinePlayer.getUniqueId().toString()).getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.type> // @returns Element // @description // Always returns 'Player' for dPlayer objects. All objects fetchable by the Object Fetcher will return the // type of object that is fulfilling this attribute. // --> if (attribute.startsWith("type")) { return new Element("Player").getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.save_name> // @returns Element // @description // Returns the ID used to save the player in Denizen's saves.yml file. // Works with offline players. // --> if (attribute.startsWith("save_name")) { return new Element(getSaveName()).getAttribute(attribute.fulfill(1)); } ///////////////////// // LOCATION ATTRIBUTES ///////////////// // <--[tag] // @attribute <p@player.bed_spawn> // @returns dLocation // @description // Returns the location of the player's bed spawn location, null if // it doesn't exist. // Works with offline players. // @mechanism dPlayer.bed_spawn_location // --> if (attribute.startsWith("bed_spawn")) { if (getOfflinePlayer().getBedSpawnLocation() == null) { return null; } return new dLocation(getOfflinePlayer().getBedSpawnLocation()) .getAttribute(attribute.fulfill(1)); } // If online, let dEntity handle location tags since there are more options // for online Players if (attribute.startsWith("location") && !isOnline()) { return getLocation().getAttribute(attribute.fulfill(1)); } ///////////////////// // STATE ATTRIBUTES ///////////////// // <--[tag] // @attribute <p@player.first_played> // @returns Duration // @description // Returns the millisecond time of when the player first logged on to this server. // Works with offline players. // --> if (attribute.startsWith("first_played")) { attribute = attribute.fulfill(1); if (attribute.startsWith("milliseconds") || attribute.startsWith("in_milliseconds")) { return new Element(getOfflinePlayer().getFirstPlayed()) .getAttribute(attribute.fulfill(1)); } return new Duration(getOfflinePlayer().getFirstPlayed() / 50) .getAttribute(attribute); } // <--[tag] // @attribute <p@player.has_played_before> // @returns Element(Boolean) // @description // Returns whether the player has played before. // Works with offline players. // Note: This will just always return true. // --> if (attribute.startsWith("has_played_before")) { return new Element(true) .getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.health.is_scaled> // @returns Element(Boolean) // @description // Returns whether the player's health bar is currently being scaled. // --> if (attribute.startsWith("health.is_scaled")) { return new Element(getPlayerEntity().isHealthScaled()) .getAttribute(attribute.fulfill(2)); } // <--[tag] // @attribute <p@player.health.scale> // @returns Element(Decimal) // @description // Returns the current scale for the player's health bar // --> if (attribute.startsWith("health.scale")) { return new Element(getPlayerEntity().getHealthScale()) .getAttribute(attribute.fulfill(2)); } // <--[tag] // @attribute <p@player.exhaustion> // @returns Element(Decimal) // @description // Returns how fast the food level drops (exhaustion). // --> if (attribute.startsWith("exhaustion")) { return new Element(getPlayerEntity().getExhaustion()) .getAttribute(attribute.fulfill(1)); } // Handle dEntity oxygen tags here to allow getting them when the player is offline if (attribute.startsWith("oxygen.max")) { return new Duration((long) getMaximumAir()).getAttribute(attribute.fulfill(2)); } if (attribute.startsWith("oxygen")) { return new Duration((long) getRemainingAir()).getAttribute(attribute.fulfill(1)); } // Same with health tags if (attribute.startsWith("health.formatted")) { return EntityHealth.getHealthFormatted(new dEntity(getPlayerEntity()), attribute); } if (attribute.startsWith("health.percentage")) { double maxHealth = getPlayerEntity().getMaxHealth(); if (attribute.hasContext(2)) { maxHealth = attribute.getIntContext(2); } return new Element((getPlayerEntity().getHealth() / maxHealth) * 100) .getAttribute(attribute.fulfill(2)); } if (attribute.startsWith("health.max")) { return new Element(getMaxHealth()).getAttribute(attribute.fulfill(2)); } if (attribute.matches("health")) { return new Element(getHealth()).getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.is_banned> // @returns Element(Boolean) // @description // Returns whether the player is banned. // @mechanism dPlayer.is_banned // --> if (attribute.startsWith("is_banned")) { BanEntry ban = Bukkit.getBanList(BanList.Type.NAME).getBanEntry(getName()); if (ban == null) { return Element.FALSE.getAttribute(attribute.fulfill(1)); } else if (ban.getExpiration() == null) { return Element.TRUE.getAttribute(attribute.fulfill(1)); } return new Element(ban.getExpiration().after(new Date())).getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.is_online> // @returns Element(Boolean) // @description // Returns whether the player is currently online. // Works with offline players (returns false in that case). // --> if (attribute.startsWith("is_online")) { return new Element(isOnline()).getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.is_op> // @returns Element(Boolean) // @description // Returns whether the player is a full server operator. // Works with offline players. // @mechanism dPlayer.is_op // --> if (attribute.startsWith("is_op")) { return new Element(getOfflinePlayer().isOp()) .getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.is_whitelisted> // @returns Element(Boolean) // @description // Returns whether the player is whitelisted. // Works with offline players. // @mechanism dPlayer.is_whitelisted // --> if (attribute.startsWith("is_whitelisted")) { return new Element(getOfflinePlayer().isWhitelisted()) .getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.last_played> // @returns Duration // @description // Returns the datestamp of when the player was last seen in duration. // Works with offline players. // --> if (attribute.startsWith("last_played")) { attribute = attribute.fulfill(1); if (attribute.startsWith("milliseconds") || attribute.startsWith("in_milliseconds")) { if (isOnline()) { return new Element(System.currentTimeMillis()) .getAttribute(attribute.fulfill(1)); } return new Element(getOfflinePlayer().getLastPlayed()) .getAttribute(attribute.fulfill(1)); } if (isOnline()) { return new Duration(System.currentTimeMillis() / 50) .getAttribute(attribute); } return new Duration(getOfflinePlayer().getLastPlayed() / 50) .getAttribute(attribute); } // <--[tag] // @attribute <p@player.groups> // @returns dList // @description // Returns a list of all groups the player is in. // May work with offline players, depending on permission plugin. // --> if (attribute.startsWith("groups")) { if (Depends.permissions == null) { if (!attribute.hasAlternative()) { dB.echoError("No permission system loaded! Have you installed Vault and a compatible permissions plugin?"); } return null; } dList list = new dList(); // TODO: optionally specify world for (String group : Depends.permissions.getGroups()) { if (Depends.permissions.playerInGroup(null, offlinePlayer, group)) { list.add(group); } } return list.getAttribute(attribute.fulfill(1)); } if (attribute.startsWith("ban_info")) { attribute.fulfill(1); BanEntry ban = Bukkit.getBanList(BanList.Type.NAME).getBanEntry(getName()); if (ban == null) { return null; } else if (ban.getExpiration() != null && ban.getExpiration().before(new Date())) { return null; } // <--[tag] // @attribute <p@player.ban_info.expiration> // @returns Duration // @description // Returns the expiration of the player's ban, if they are banned. // Potentially can be null. // --> if (attribute.startsWith("expiration") && ban.getExpiration() != null) { return new Duration(ban.getExpiration().getTime() / 50) .getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.ban_info.reason> // @returns Element // @description // Returns the reason for the player's ban, if they are banned. // --> else if (attribute.startsWith("reason")) { return new Element(ban.getReason()) .getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.ban_info.created> // @returns Duration // @description // Returns when the player's ban was created, if they are banned. // --> else if (attribute.startsWith("created")) { return new Duration(ban.getCreated().getTime() / 50) .getAttribute(attribute.fulfill(1)); } return null; } // <--[tag] // @attribute <p@player.in_group[<group_name>]> // @returns Element(Boolean) // @description // Returns whether the player is in the specified group (requires the player to be online) // --> if (attribute.startsWith("in_group")) { if (Depends.permissions == null) { if (!attribute.hasAlternative()) { dB.echoError("No permission system loaded! Have you installed Vault and a compatible permissions plugin?"); } return null; } String group = attribute.getContext(1); // <--[tag] // @attribute <p@player.in_group[<group_name>].global> // @returns Element(Boolean) // @description // Returns whether the player has the group with no regard to the // player's current world. // (Works with offline players) // (Note: This may or may not be functional with your permissions system.) // --> // Non-world specific permission if (attribute.getAttribute(2).startsWith("global")) { return new Element(Depends.permissions.playerInGroup((World) null, getName(), group)) // TODO: Vault UUID support? .getAttribute(attribute.fulfill(2)); } // <--[tag] // @attribute <p@player.in_group[<group_name>].world> // @returns Element(Boolean) // @description // Returns whether the player has the group in regards to the // player's current world. // (Works with offline players) // (Note: This may or may not be functional with your permissions system.) // --> // Permission in certain world else if (attribute.getAttribute(2).startsWith("world")) { return new Element(Depends.permissions.playerInGroup(attribute.getContext(2), getName(), group)) // TODO: Vault UUID support? .getAttribute(attribute.fulfill(2)); } // Permission in current world else if (isOnline()) { return new Element(Depends.permissions.playerInGroup(getPlayerEntity(), group)) .getAttribute(attribute.fulfill(1)); } } // <--[tag] // @attribute <p@player.has_permission[permission.node]> // @returns Element(Boolean) // @description // Returns whether the player has the specified node. // (Requires the player to be online) // --> if (attribute.startsWith("permission") || attribute.startsWith("has_permission")) { String permission = attribute.getContext(1); // <--[tag] // @attribute <p@player.has_permission[permission.node].global> // @returns Element(Boolean) // @description // Returns whether the player has the specified node, regardless of world. // (Works with offline players) // (Note: this may or may not be functional with your permissions system.) // --> // Non-world specific permission if (attribute.getAttribute(2).startsWith("global")) { if (Depends.permissions == null) { if (!attribute.hasAlternative()) { dB.echoError("No permission system loaded! Have you installed Vault and a compatible permissions plugin?"); } return null; } return new Element(Depends.permissions.has((World) null, getName(), permission)) // TODO: Vault UUID support? .getAttribute(attribute.fulfill(2)); } // <--[tag] // @attribute <p@player.has_permission[permission.node].world[<world name>]> // @returns Element(Boolean) // @description // Returns whether the player has the specified node in regards to the // specified world. // (Works with offline players) // (Note: This may or may not be functional with your permissions system.) // --> // Permission in certain world else if (attribute.getAttribute(2).startsWith("world")) { if (Depends.permissions == null) { if (!attribute.hasAlternative()) { dB.echoError("No permission system loaded! Have you installed Vault and a compatible permissions plugin?"); } return null; } return new Element(Depends.permissions.has(attribute.getContext(2), getName(), permission)) // TODO: Vault UUID support? .getAttribute(attribute.fulfill(2)); } // Permission in current world else if (isOnline()) { return new Element(getPlayerEntity().hasPermission(permission)) .getAttribute(attribute.fulfill(1)); } } ///////////////////// // INVENTORY ATTRIBUTES ///////////////// // <--[tag] // @attribute <p@player.inventory> // @returns dInventory // @description // Returns a dInventory of the player's current inventory. // Works with offline players. // --> if (attribute.startsWith("inventory")) { return getInventory().getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.enderchest> // @returns dInventory // @description // Gets the player's enderchest inventory. // Works with offline players. // --> if (attribute.startsWith("enderchest")) { return getEnderChest().getAttribute(attribute.fulfill(1)); } ///////////////////// // ONLINE ATTRIBUTES ///////////////// // Player is required to be online after this point... if (!isOnline()) { return new Element(identify()).getAttribute(attribute); } // <--[tag] // @attribute <p@player.open_inventory> // @returns dInventory // @description // Gets the inventory the player currently has open. If the player has no open // inventory, this returns the player's inventory. // --> if (attribute.startsWith("open_inventory")) { return new dInventory(getPlayerEntity().getOpenInventory().getTopInventory()) .getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.item_on_cursor> // @returns dItem // @description // Returns the item on the player's cursor, if any. This includes // chest interfaces, inventories, and hotbars, etc. // --> if (attribute.startsWith("item_on_cursor")) { return new dItem(getPlayerEntity().getItemOnCursor()) .getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.item_in_hand.slot> // @returns Element(Number) // @description // Returns the slot location of the player's selected item. // --> if (attribute.startsWith("item_in_hand.slot")) { return new Element(getPlayerEntity().getInventory().getHeldItemSlot() + 1) .getAttribute(attribute.fulfill(2)); } // <--[tag] // @attribute <p@player.sidebar.lines> // @returns dList // @description // Returns the current lines set on the player's Sidebar via the Sidebar command. // --> if (attribute.startsWith("sidebar.lines")) { Sidebar sidebar = SidebarCommand.getSidebar(this); if (sidebar == null) { return null; } return new dList(sidebar.getLines()).getAttribute(attribute.fulfill(2)); } // <--[tag] // @attribute <p@player.sidebar.title> // @returns Element // @description // Returns the current title set on the player's Sidebar via the Sidebar command. // --> if (attribute.startsWith("sidebar.title")) { Sidebar sidebar = SidebarCommand.getSidebar(this); if (sidebar == null) { return null; } return new Element(sidebar.getTitle()).getAttribute(attribute.fulfill(2)); } // <--[tag] // @attribute <p@player.sidebar.scores> // @returns dList(Element(Number)) // @description // Returns the current scores set on the player's Sidebar via the Sidebar command, // in the same order as <@link tag p@player.sidebar.lines>. // --> if (attribute.startsWith("sidebar.scores")) { Sidebar sidebar = SidebarCommand.getSidebar(this); if (sidebar == null) { return null; } dList scores = new dList(); for (int score : sidebar.getScores()) { scores.add(String.valueOf(score)); } return scores.getAttribute(attribute.fulfill(2)); } // <--[tag] // @attribute <p@player.sidebar.start> // @returns Element(Number) // @description // Returns the current start score set on the player's Sidebar via the Sidebar command. // --> if (attribute.startsWith("sidebar.start")) { Sidebar sidebar = SidebarCommand.getSidebar(this); if (sidebar == null) { return null; } return new Element(sidebar.getStart()).getAttribute(attribute.fulfill(2)); } // <--[tag] // @attribute <p@player.sidebar.increment> // @returns Element(Number) // @description // Returns the current score increment set on the player's Sidebar via the Sidebar command. // --> if (attribute.startsWith("sidebar.increment")) { Sidebar sidebar = SidebarCommand.getSidebar(this); if (sidebar == null) { return null; } return new Element(sidebar.getIncrement()).getAttribute(attribute.fulfill(2)); } // <--[tag] // @attribute <p@player.skin_blob> // @returns Element // @description // Returns the player's current skin blob. // @mechanism dPlayer.skin_blob // --> if (attribute.startsWith("skin_blob")) { return new Element(NMSHandler.getInstance().getProfileEditor().getPlayerSkinBlob(getPlayerEntity())) .getAttribute(attribute.fulfill(1)); } ///////////////////// // CITIZENS ATTRIBUTES ///////////////// // <--[tag] // @attribute <p@player.selected_npc> // @returns dNPC // @description // Returns the dNPC that the player currently has selected with // '/npc select', null if no player selected. // --> if (attribute.startsWith("selected_npc")) { if (getPlayerEntity().hasMetadata("selected")) { return getSelectedNPC().getAttribute(attribute.fulfill(1)); } } ///////////////////// // CONVERSION ATTRIBUTES ///////////////// // <--[tag] // @attribute <p@player.entity> // @returns dEntity // @description // Returns the dEntity object of the player. // (Note: This should never actually be needed. <p@player> is considered a valid dEntity by script commands.) // --> if (attribute.startsWith("entity") && !attribute.startsWith("entity_")) { return new dEntity(getPlayerEntity()) .getAttribute(attribute.fulfill(1)); } ///////////////////// // IDENTIFICATION ATTRIBUTES ///////////////// // <--[tag] // @attribute <p@player.ip> // @returns Element // @description // Returns the player's IP address host name. // --> if (attribute.startsWith("ip") || attribute.startsWith("host_name")) { attribute = attribute.fulfill(1); // <--[tag] // @attribute <p@player.ip.address_only> // @returns Element // @description // Returns the player's IP address. // --> if (attribute.startsWith("address_only")) { return new Element(getPlayerEntity().getAddress().toString()) .getAttribute(attribute.fulfill(1)); } String host = getPlayerEntity().getAddress().getHostName(); // <--[tag] // @attribute <p@player.ip.address> // @returns Element // @description // Returns the player's IP address. // --> if (attribute.startsWith("address")) { return new Element(getPlayerEntity().getAddress().toString()) .getAttribute(attribute.fulfill(1)); } return new Element(host) .getAttribute(attribute); } // <--[tag] // @attribute <p@player.name.display> // @returns Element // @description // Returns the display name of the player, which may contain // prefixes and suffixes, colors, etc. // --> if (attribute.startsWith("name.display")) { return new Element(getPlayerEntity().getDisplayName()) .getAttribute(attribute.fulfill(2)); } // <--[tag] // @attribute <p@player.name.list> // @returns Element // @description // Returns the name of the player as shown in the player list. // --> if (attribute.startsWith("name.list")) { return new Element(getPlayerEntity().getPlayerListName()) .getAttribute(attribute.fulfill(2)); } // <--[tag] // @attribute <p@player.nameplate> // @returns Element // @description // Returns the displayed text in the nameplate of the player. // --> if (attribute.startsWith("nameplate")) { return new Element(NMSHandler.getInstance().getProfileEditor().getPlayerName(getPlayerEntity())) .getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.name> // @returns Element // @description // Returns the name of the player. // --> if (attribute.startsWith("name")) { return new Element(getName()).getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.has_finished[<script>]> // @returns Element(Boolean) // @description // Returns whether the player has finished the specified script. // --> if (attribute.startsWith("has_finished")) { dScript script = dScript.valueOf(attribute.getContext(1)); if (script == null) { return Element.FALSE.getAttribute(attribute.fulfill(1)); } return new Element(FinishCommand.getScriptCompletes(getName(), script.getName()) > 0) .getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.has_failed[<script>]> // @returns Element(Boolean) // @description // Returns whether the player has failed the specified script. // --> if (attribute.startsWith("has_failed")) { dScript script = dScript.valueOf(attribute.getContext(1)); if (script == null) { return Element.FALSE.getAttribute(attribute.fulfill(1)); } return new Element(FailCommand.getScriptFails(getName(), script.getName()) > 0) .getAttribute(attribute.fulfill(1)); } ///////////////////// // LOCATION ATTRIBUTES ///////////////// // <--[tag] // @attribute <p@player.compass_target> // @returns dLocation // @description // Returns the location of the player's compass target. // --> if (attribute.startsWith("compass_target")) { Location target = getPlayerEntity().getCompassTarget(); if (target != null) { return new dLocation(target).getAttribute(attribute.fulfill(1)); } } // <--[tag] // @attribute <p@player.chunk_loaded[<chunk>]> // @returns Element(Boolean) // @description // Returns whether the player has the chunk loaded on their client. // --> if (attribute.startsWith("chunk_loaded") && attribute.hasContext(1)) { dChunk chunk = dChunk.valueOf(attribute.getContext(1)); if (chunk == null) { return null; } return new Element(hasChunkLoaded(chunk.chunk)).getAttribute(attribute.fulfill(1)); } ///////////////////// // STATE ATTRIBUTES ///////////////// // <--[tag] // @attribute <p@player.can_fly> // @returns Element(Boolean) // @description // Returns whether the player is allowed to fly. // @mechanism dPlayer.can_fly // --> if (attribute.startsWith("can_fly") || attribute.startsWith("allowed_flight")) { return new Element(getPlayerEntity().getAllowFlight()) .getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.fly_speed> // @returns Element(Decimal) // @description // Returns the speed the player can fly at. // --> if (attribute.startsWith("fly_speed")) { return new Element(getPlayerEntity().getFlySpeed()) .getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.food_level.formatted> // @returns Element // @description // Returns a 'formatted' value of the player's current food level. // May be 'starving', 'famished', 'parched, 'hungry' or 'healthy'. // --> if (attribute.startsWith("food_level.formatted")) { double maxHunger = getPlayerEntity().getMaxHealth(); if (attribute.hasContext(2)) { maxHunger = attribute.getIntContext(2); } int foodLevel = getFoodLevel(); if (foodLevel / maxHunger < .10) { return new Element("starving").getAttribute(attribute.fulfill(2)); } else if (foodLevel / maxHunger < .40) { return new Element("famished").getAttribute(attribute.fulfill(2)); } else if (foodLevel / maxHunger < .75) { return new Element("parched").getAttribute(attribute.fulfill(2)); } else if (foodLevel / maxHunger < 1) { return new Element("hungry").getAttribute(attribute.fulfill(2)); } else { return new Element("healthy").getAttribute(attribute.fulfill(2)); } } // <--[tag] // @attribute <p@player.saturation> // @returns Element(Decimal) // @description // Returns the current saturation of the player. // --> if (attribute.startsWith("saturation")) { return new Element(getPlayerEntity().getSaturation()) .getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.food_level> // @returns Element(Number) // @description // Returns the current food level of the player. // --> if (attribute.startsWith("food_level")) { return new Element(getFoodLevel()) .getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.gamemode> // @returns Element // @description // Returns the name of the gamemode the player is currently set to. // --> if (attribute.startsWith("gamemode")) { attribute = attribute.fulfill(1); // <--[tag] // @attribute <p@player.gamemode.id> // @returns Element(Number) // @description // Returns the gamemode ID of the player. 0 = survival, 1 = creative, 2 = adventure, 3 = spectator // --> if (attribute.startsWith("id")) { return new Element(getPlayerEntity().getGameMode().getValue()) .getAttribute(attribute.fulfill(1)); } return new Element(getPlayerEntity().getGameMode().name()) .getAttribute(attribute); } // <--[tag] // @attribute <p@player.is_blocking> // @returns Element(Boolean) // @description // Returns whether the player is currently blocking. // --> if (attribute.startsWith("is_blocking")) { return new Element(getPlayerEntity().isBlocking()) .getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.ping> // @returns Element(Number) // @description // Returns the player's current ping. // --> if (attribute.startsWith("ping")) { return new Element(NMSHandler.getInstance().getPlayerHelper().getPing(getPlayerEntity())) .getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.is_flying> // @returns Element(Boolean) // @description // Returns whether the player is currently flying. // --> if (attribute.startsWith("is_flying")) { return new Element(getPlayerEntity().isFlying()) .getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.is_sleeping> // @returns Element(Boolean) // @description // Returns whether the player is currently sleeping. // --> if (attribute.startsWith("is_sleeping")) { return new Element(getPlayerEntity().isSleeping()) .getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.is_sneaking> // @returns Element(Boolean) // @description // Returns whether the player is currently sneaking. // --> if (attribute.startsWith("is_sneaking")) { return new Element(getPlayerEntity().isSneaking()) .getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.is_sprinting> // @returns Element(Boolean) // @description // Returns whether the player is currently sprinting. // --> if (attribute.startsWith("is_sprinting")) { return new Element(getPlayerEntity().isSprinting()) .getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.has_achievement[<achievement>]> // @returns Element(Boolean) // @description // Returns whether the player has the specified achievement. // --> if (attribute.startsWith("has_achievement")) { Achievement ach = Achievement.valueOf(attribute.getContext(1).toUpperCase()); return new Element(getPlayerEntity().hasAchievement(ach)).getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.statistic[<statistic>]> // @returns Element(Number) // @description // Returns the player's current value for the specified statistic. // --> if (attribute.startsWith("statistic")) { Statistic statistic = Statistic.valueOf(attribute.getContext(1).toUpperCase()); if (statistic == null) { return null; } // <--[tag] // @attribute <p@player.statistic[<statistic>].qualifier[<material>/<entity>]> // @returns Element(Number) // @description // Returns the player's current value for the specified statistic, with the // specified qualifier, which can be either an entity or material. // --> if (attribute.getAttribute(2).startsWith("qualifier")) { dObject obj = ObjectFetcher.pickObjectFor(attribute.getContext(2)); try { if (obj instanceof dMaterial) { return new Element(getPlayerEntity().getStatistic(statistic, ((dMaterial) obj).getMaterial())) .getAttribute(attribute.fulfill(2)); } else if (obj instanceof dEntity) { return new Element(getPlayerEntity().getStatistic(statistic, ((dEntity) obj).getBukkitEntityType())) .getAttribute(attribute.fulfill(2)); } else { return null; } } catch (Exception e) { dB.echoError("Invalid statistic: " + statistic + " for this player!"); return null; } } try { return new Element(getPlayerEntity().getStatistic(statistic)).getAttribute(attribute.fulfill(1)); } catch (Exception e) { dB.echoError("Invalid statistic: " + statistic + " for this player!"); return null; } } // <--[tag] // @attribute <p@player.time_asleep> // @returns Duration // @description // Returns the time the player has been asleep. // --> if (attribute.startsWith("time_asleep")) { return new Duration(getPlayerEntity().getSleepTicks() / 20) .getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.time> // @returns Element(Number) // @description // Returns the time the player is currently experiencing. This time could differ from // the time that the rest of the world is currently experiencing if a 'time' or 'freeze_time' // mechanism is being used on the player. // --> if (attribute.startsWith("time")) { return new Element(getPlayerEntity().getPlayerTime()) .getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.walk_speed> // @returns Element(Decimal) // @description // Returns the speed the player can walk at. // --> if (attribute.startsWith("walk_speed")) { return new Element(getPlayerEntity().getWalkSpeed()) .getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.weather> // @returns Element // @description // Returns the type of weather the player is experiencing. This will be different // from the weather currently in the world that the player is residing in if // the weather is currently being forced onto the player. // Returns null if the player does not currently have any forced weather. // --> if (attribute.startsWith("weather")) { if (getPlayerEntity().getPlayerWeather() != null) { return new Element(getPlayerEntity().getPlayerWeather().name()) .getAttribute(attribute.fulfill(1)); } else { return null; } } // <--[tag] // @attribute <p@player.xp.level> // @returns Element(Number) // @description // Returns the number of XP levels the player has. // --> if (attribute.startsWith("xp.level")) { return new Element(getPlayerEntity().getLevel()) .getAttribute(attribute.fulfill(2)); } // <--[tag] // @attribute <p@player.xp.to_next_level> // @returns Element(Number) // @description // Returns the amount of XP needed to get to the next level. // --> if (attribute.startsWith("xp.to_next_level")) { return new Element(getPlayerEntity().getExpToLevel()) .getAttribute(attribute.fulfill(2)); } // <--[tag] // @attribute <p@player.xp.total> // @returns Element(Number) // @description // Returns the total amount of experience points. // --> if (attribute.startsWith("xp.total")) { return new Element(getPlayerEntity().getTotalExperience()) .getAttribute(attribute.fulfill(2)); } // <--[tag] // @attribute <p@player.xp> // @returns Element(Decimal) // @description // Returns the percentage of experience points to the next level. // --> if (attribute.startsWith("xp")) { return new Element(getPlayerEntity().getExp() * 100) .getAttribute(attribute.fulfill(1)); } if (Depends.chat != null) { // <--[tag] // @attribute <p@player.chat_prefix> // @returns Element // @description // Returns the player's chat prefix. // NOTE: May work with offline players. // @mechanism dPlayer.chat_prefix // --> if (attribute.startsWith("chat_prefix")) { String prefix = Depends.chat.getPlayerPrefix(getWorld().getName(), getOfflinePlayer()); if (prefix == null) { return null; } return new Element(prefix).getAttribute(attribute.fulfill(1)); } // <--[tag] // @attribute <p@player.chat_suffix> // @returns Element // @description // Returns the player's chat suffix. // NOTE: May work with offline players. // @mechanism dPlayer.chat_suffix // --> else if (attribute.startsWith("chat_suffix")) { String suffix = Depends.chat.getPlayerSuffix(getWorld().getName(), getOfflinePlayer()); if (suffix == null) { return null; } return new Element(suffix).getAttribute(attribute.fulfill(1)); } } // Iterate through this object's properties' attributes for (Property property : PropertyParser.getProperties(this)) { String returned = property.getAttribute(attribute); if (returned != null) { return returned; } } return new dEntity(getPlayerEntity()).getAttribute(attribute); } public void applyProperty(Mechanism mechanism) { dB.echoError("Cannot apply properties to a player!"); } @Override public void adjust(Mechanism mechanism) { Element value = mechanism.getValue(); // <--[mechanism] // @object dPlayer // @name level // @input Element(Number) // @description // Sets the level on the player. Does not affect the current progression // of experience towards next level. // @tags // <p@player.xp.level> // --> if (mechanism.matches("level") && mechanism.requireInteger()) { setLevel(value.asInt()); } // <--[mechanism] // @object dPlayer // @name item_slot // @input Element(Number) // @description // Sets the inventory slot that the player has selected. // Works with offline players. // @tags // <p@player.item_in_hand.slot> // --> if (mechanism.matches("item_slot") && mechanism.requireInteger()) { if (isOnline()) { getPlayerEntity().getInventory().setHeldItemSlot(value.asInt() - 1); } else { getNBTEditor().setItemInHand(value.asInt() - 1); } } // <--[mechanism] // @object dPlayer // @name item_on_cursor // @input dItem // @description // Sets the item on the player's cursor. This includes // chest interfaces, inventories, and hotbars, etc. // @tags // <p@player.item_on_cursor> // --> if (mechanism.matches("item_on_cursor") && mechanism.requireObject(dItem.class)) { getPlayerEntity().setItemOnCursor(value.asType(dItem.class).getItemStack()); } // <--[mechanism] // @object dPlayer // @name award_achievement // @input Element // @description // Awards an achievement to the player. Valid achievements: // ACQUIRE_IRON, BAKE_CAKE, BOOKCASE, BREED_COW, BREW_POTION, BUILD_BETTER_PICKAXE, // BUILD_FURNACE, BUILD_HOE, BUILD_PICKAXE, BUILD_SWORD, BUILD_WORKBENCH, COOK_FISH, // DIAMONDS_TO_YOU, ENCHANTMENTS, END_PORTAL, EXPLORE_ALL_BIOMES, FLY_PIG, FULL_BEACON, // GET_BLAZE_ROD, GET_DIAMONDS, GHAST_RETURN, KILL_COW, KILL_ENEMY, KILL_WITHER, // MAKE_BREAD, MINE_WOOD, NETHER_PORTAL, ON_A_RAIL, OPEN_INVENTORY, OVERKILL, // SNIPE_SKELETON, SPAWN_WITHER, THE_END // @tags // None // --> // TODO: Player achievement tags. if (mechanism.matches("award_achievement") && mechanism.requireEnum(false, Achievement.values())) { getPlayerEntity().awardAchievement(Achievement.valueOf(value.asString().toUpperCase())); } // <--[mechanism] // @object dPlayer // @name health_scale // @input Element(Decimal) // @description // Sets the 'health scale' on the Player. Each heart equals '2'. The standard health scale is // 20, so for example, indicating a value of 40 will display double the amount of hearts // standard. // Player relogging will reset this mechanism. // @tags // <p@player.health.scale> // --> if (mechanism.matches("health_scale") && mechanism.requireDouble()) { getPlayerEntity().setHealthScale(value.asDouble()); } // <--[mechanism] // @object dPlayer // @name scale_health // @input Element(Boolean) // @description // Enables or disables the health scale value. Disabling will result in the standard // amount of hearts being shown. // @tags // <p@player.health.is_scaled> // --> if (mechanism.matches("scale_health") && mechanism.requireBoolean()) { getPlayerEntity().setHealthScaled(value.asBoolean()); } // Allow offline editing of health values if (mechanism.matches("max_health") && mechanism.requireDouble()) { setMaxHealth(value.asDouble()); } if (mechanism.matches("health") && mechanism.requireDouble()) { setHealth(value.asDouble()); } // <--[mechanism] // @object dPlayer // @name resource_pack // @input Element // @description // Sets the current resource pack by specifying a valid URL to a resource pack. // @tags // None // --> if (mechanism.matches("resource_pack") || mechanism.matches("texture_pack")) { getPlayerEntity().setResourcePack(value.asString()); } // <--[mechanism] // @object dPlayer // @name saturation // @input Element(Decimal) // @description // Sets the current food saturation level of a player. // @tags // <p@player.saturation> // --> if (mechanism.matches("saturation") && mechanism.requireFloat()) { getPlayerEntity().setSaturation(value.asFloat()); } // <--[mechanism] // @object dPlayer // @name send_map // @input Element(Number) // @description // Forces a player to receive the entirety of the specified map ID instantly. // @tags // None // --> if (mechanism.matches("send_map") && mechanism.requireInteger()) { MapView map = Bukkit.getServer().getMap((short) value.asInt()); if (map != null) { getPlayerEntity().sendMap(map); } else { dB.echoError("No map found for ID " + value.asInt() + "!"); } } // <--[mechanism] // @object dPlayer // @name food_level // @input Element(Number) // @description // Sets the current food level of a player. Typically, '20' is full. // @tags // <p@player.food_level> // --> if (mechanism.matches("food_level") && mechanism.requireInteger()) { setFoodLevel(value.asInt()); } // <--[mechanism] // @object dPlayer // @name bed_spawn_location // @input dLocation // @description // Sets the bed location that the player respawns at. // @tags // <p@player.bed_spawn> // --> if (mechanism.matches("bed_spawn_location") && mechanism.requireObject(dLocation.class)) { setBedSpawnLocation(value.asType(dLocation.class)); } // <--[mechanism] // @object dPlayer // @name can_fly // @input Element(Boolean) // @description // Sets whether the player is allowed to fly. // @tags // <p@player.can_fly> // --> if (mechanism.matches("can_fly") && mechanism.requireBoolean()) { getPlayerEntity().setAllowFlight(value.asBoolean()); } // <--[mechanism] // @object dPlayer // @name fly_speed // @input Element(Decimal) // @description // Sets the fly speed of the player. Valid range is 0.0 to 1.0 // @tags // <p@player.fly_speed> // --> if (mechanism.matches("fly_speed") && mechanism.requireFloat()) { setFlySpeed(value.asFloat()); } // <--[mechanism] // @object dPlayer // @name flying // @input Element(Boolean) // @description // Sets whether the player is flying. // @tags // <p@player.is_flying> // --> if (mechanism.matches("flying") && mechanism.requireBoolean()) { getPlayerEntity().setFlying(value.asBoolean()); } // <--[mechanism] // @object dPlayer // @name gamemode // @input Element // @description // Sets the game mode of the player. // Valid gamemodes are survival, creative, adventure, and spectator. // @tags // <p@player.gamemode> // <p@player.gamemode.id> // --> if (mechanism.matches("gamemode") && mechanism.requireEnum(false, GameMode.values())) { setGameMode(GameMode.valueOf(value.asString().toUpperCase())); } // <--[mechanism] // @object dPlayer // @name kick // @input Element // @description // Kicks the player, with the specified message. // @tags // None // --> if (mechanism.matches("kick")) { getPlayerEntity().kickPlayer(mechanism.getValue().asString()); } // <--[mechanism] // @object dPlayer // @name weather // @input Element // @description // Sets the weather condition for the player. This does NOT affect the weather // in the world, and will block any world weather changes until the 'reset_weather' // mechanism is used. Valid weather: CLEAR, DOWNFALL // @tags // <p@player.weather> // --> if (mechanism.matches("weather") && mechanism.requireEnum(false, WeatherType.values())) { getPlayerEntity().setPlayerWeather(WeatherType.valueOf(value.asString().toUpperCase())); } // <--[mechanism] // @object dPlayer // @name reset_weather // @input None // @description // Resets the weather on the Player to the conditions currently taking place in the Player's // current world. // @tags // <p@player.weather> // --> if (mechanism.matches("reset_weather")) { getPlayerEntity().resetPlayerWeather(); } // <--[mechanism] // @object dPlayer // @name player_list_name // @input Element // @description // Sets the entry that is shown in the 'player list' that is shown when pressing tab. // @tags // <p@player.name.list> // --> if (mechanism.matches("player_list_name")) { getPlayerEntity().setPlayerListName(value.asString()); } // <--[mechanism] // @object dPlayer // @name display_name // @input Element // @description // Sets the name displayed for the player when chatting. // @tags // <p@player.name.display> // --> if (mechanism.matches("display_name")) { getPlayerEntity().setDisplayName(value.asString()); return; } // <--[mechanism] // @object dPlayer // @name show_workbench // @input dLocation // @description // Shows the player a workbench GUI corresponding to a given location. // @tags // None // --> if (mechanism.matches("show_workbench") && mechanism.requireObject(dLocation.class)) { getPlayerEntity().openWorkbench(mechanism.getValue().asType(dLocation.class), true); return; } // <--[mechanism] // @object dPlayer // @name location // @input dLocation // @description // If the player is online, teleports the player to a given location. // Otherwise, sets the player's next spawn location. // @tags // <p@player.location> // --> if (mechanism.matches("location") && mechanism.requireObject(dLocation.class)) { setLocation(value.asType(dLocation.class)); } // <--[mechanism] // @object dPlayer // @name time // @input Element(Number) // @description // Sets the time of day the Player is currently experiencing. Setting this will cause the // player to have a different time than other Players in the world are experiencing though // time will continue to progress. Using the 'reset_time' mechanism, or relogging your player // will reset this mechanism to match the world's current time. Valid range is 0-24000 // @tags // <p@player.time> // --> if (mechanism.matches("time") && mechanism.requireInteger()) { getPlayerEntity().setPlayerTime(value.asInt(), true); } // <--[mechanism] // @object dPlayer // @name freeze_time // @input Element(Number) // @description // Sets the time of day the Player is currently experiencing and freezes it there. Note: // there is a small 'twitch effect' when looking at the sky when time is frozen. // Setting this will cause the player to have a different time than other Players in // the world are experiencing. Using the 'reset_time' mechanism, or relogging your player // will reset this mechanism to match the world's current time. Valid range is 0-24000 // @tags // <p@player.time> // --> if (mechanism.matches("freeze_time")) { if (mechanism.requireInteger("Invalid integer specified. Assuming current world time.")) { getPlayerEntity().setPlayerTime(value.asInt(), false); } else { getPlayerEntity().setPlayerTime(getPlayerEntity().getWorld().getTime(), false); } } // <--[mechanism] // @object dPlayer // @name reset_time // @input None // @description // Resets any altered time that has been applied to this player. Using this will make // the Player's time match the world's current time. // @tags // <p@player.time> // --> if (mechanism.matches("reset_time")) { getPlayerEntity().resetPlayerTime(); } // <--[mechanism] // @object dPlayer // @name walk_speed // @input Element(Decimal) // @description // Sets the walk speed of the player. The standard value is '0.2'. Valid range is 0.0 to 1.0 // @tags // <p@player.walk_speed> // --> if (mechanism.matches("walk_speed") && mechanism.requireFloat()) { getPlayerEntity().setWalkSpeed(value.asFloat()); } // <--[mechanism] // @object dPlayer // @name exhaustion // @input Element(Decimal) // @description // Sets the exhaustion level of a player. // @tags // <p@player.exhaustion> // --> if (mechanism.matches("exhaustion") && mechanism.requireFloat()) { getPlayerEntity().setExhaustion(value.asFloat()); } // <--[mechanism] // @object dPlayer // @name show_entity // @input dEntity // @description // Shows the player a previously hidden entity. // --> if (mechanism.matches("show_entity") && mechanism.requireObject(dEntity.class)) { NMSHandler.getInstance().getEntityHelper().unhideEntity(getPlayerEntity(), value.asType(dEntity.class).getBukkitEntity()); } // <--[mechanism] // @object dPlayer // @name hide_entity // @input dEntity(|Element(Boolean)) // @description // Hides an entity from the player. You can optionally also specify a boolean to determine // whether the entity should be kept in the tab list (players only). // --> if (mechanism.matches("hide_entity")) { if (!value.asString().isEmpty()) { String[] split = value.asString().split("[\\|" + dList.internal_escape + "]", 2); if (split.length > 0 && new Element(split[0]).matchesType(dEntity.class)) { dEntity entity = value.asType(dEntity.class); if (!entity.isSpawned()) { dB.echoError("Can't hide the unspawned entity '" + split[0] + "'!"); } else if (split.length > 1 && new Element(split[1]).isBoolean()) { NMSHandler.getInstance().getEntityHelper().hideEntity(getPlayerEntity(), entity.getBukkitEntity(), new Element(split[1]).asBoolean()); } else { NMSHandler.getInstance().getEntityHelper().hideEntity(getPlayerEntity(), entity.getBukkitEntity(), false); } } else { dB.echoError("'" + split[0] + "' is not a valid entity!"); } } } // <--[mechanism] // @object dPlayer // @name show_boss_bar // @input (Element(Number)|)Element // @description // Shows the player a boss health bar with the specified text as a name. // Use with no input value to remove the bar. // Optionally, precede the text with a number indicating the health value // based on an arbitrary scale of 0 to 200. For example: // - adjust <player> show_boss_bar:Hello // - adjust <player> show_boss_bar:100|Hello // NOTE: This has been replaced by <@link command bossbar>! // @tags // None // --> if (mechanism.matches("show_boss_bar")) { if (!value.asString().isEmpty()) { String[] split = value.asString().split("[\\|" + dList.internal_escape + "]", 2); if (split.length == 2 && new Element(split[0]).isDouble()) { NMSHandler.getInstance().getPlayerHelper().showSimpleBossBar(getPlayerEntity(), split[1], new Element(split[0]).asDouble()/200); } else { NMSHandler.getInstance().getPlayerHelper().showSimpleBossBar(getPlayerEntity(), split[0], 1.0); } } else { NMSHandler.getInstance().getPlayerHelper().removeSimpleBossBar(getPlayerEntity()); } } // <--[mechanism] // @object dPlayer // @name fake_experience // @input Element(Decimal)(|Element(Number)) // @description // Shows the player a fake experience bar, with a number between 0.0 and 1.0 // to specify how far along the bar is. // Use with no input value to reset to the player's normal experience. // Optionally, you can specify a fake experience level. // - adjust <player> fake_experience:0.5|5 // @tags // None // --> if (mechanism.matches("fake_experience")) { if (!value.asString().isEmpty()) { String[] split = value.asString().split("[\\|" + dList.internal_escape + "]", 2); if (split.length > 0 && new Element(split[0]).isFloat()) { if (split.length > 1 && new Element(split[1]).isInt()) { NMSHandler.getInstance().getPacketHelper().showExperience(getPlayerEntity(), new Element(split[0]).asFloat(), new Element(split[1]).asInt()); } else { NMSHandler.getInstance().getPacketHelper().showExperience(getPlayerEntity(), new Element(split[0]).asFloat(), getPlayerEntity().getLevel()); } } else { dB.echoError("'" + split[0] + "' is not a valid decimal number!"); } } else { NMSHandler.getInstance().getPacketHelper().resetExperience(getPlayerEntity()); } } // <--[mechanism] // @object dPlayer // @name fake_health // @input Element(Decimal)(|Element(Number)(|Element(Decimal))) // @description // Shows the player a fake health bar, with a number between 0 and 20, // where 1 is half of a heart. // Use with no input value to reset to the player's normal health. // Optionally, you can specify a fake food level, between 0 and 20. // You can also optionally specify a food saturation level between 0 and 10. // - adjust <player> fake_health:1 // - adjust <player> fake_health:10|15 // - adjust <player> fake_health:<player.health>|3|0 // @tags // None // --> if (mechanism.matches("fake_health")) { if (!value.asString().isEmpty()) { String[] split = value.asString().split("[\\|" + dList.internal_escape + "]", 3); if (split.length > 0 && new Element(split[0]).isFloat()) { if (split.length > 1 && new Element(split[1]).isInt()) { if (split.length > 2 && new Element(split[2]).isFloat()) { NMSHandler.getInstance().getPacketHelper().showHealth(getPlayerEntity(), new Element(split[0]).asFloat(), new Element(split[1]).asInt(), new Element(split[2]).asFloat()); } else { NMSHandler.getInstance().getPacketHelper().showHealth(getPlayerEntity(), new Element(split[0]).asFloat(), new Element(split[1]).asInt(), getPlayerEntity().getSaturation()); } } else { NMSHandler.getInstance().getPacketHelper().showHealth(getPlayerEntity(), new Element(split[0]).asFloat(), getPlayerEntity().getFoodLevel(), getPlayerEntity().getSaturation()); } } else { dB.echoError("'" + split[0] + "' is not a valid decimal number!"); } } else { NMSHandler.getInstance().getPacketHelper().resetHealth(getPlayerEntity()); } } // <--[mechanism] // @object dPlayer // @name fake_equipment // @input dEntity(|Element|dItem) // @description // Shows the player fake equipment on the specified living entity, which has // no real non-visual effects, in the form Entity|Slot|Item, where the slot // can be one of the following: HAND, OFF_HAND, BOOTS, LEGS, CHEST, HEAD // Optionally, exclude the slot and item to stop showing the fake equipment, // if any, on the specified entity. // - adjust <player> fake_equipment:e@123|chest|i@diamond_chestplate // - adjust <player> fake_equipment:<player>|head|i@jack_o_lantern // --> if (mechanism.matches("fake_equipment")) { if (!value.asString().isEmpty()) { String[] split = value.asString().split("[\\|" + dList.internal_escape + "]", 3); if (split.length > 0 && new Element(split[0]).matchesType(dEntity.class)) { String slot = split[1].toUpperCase(); if (split.length > 1 && (new Element(slot).matchesEnum(EquipmentSlot.values()) || slot.equals("MAIN_HAND") || slot.equals("BOOTS"))) { if (split.length > 2 && new Element(split[2]).matchesType(dItem.class)) { if (slot.equals("MAIN_HAND")) { slot = "HAND"; } else if (slot.equals("BOOTS")) { slot = "FEET"; } NMSHandler.getInstance().getPacketHelper().showEquipment(getPlayerEntity(), new Element(split[0]).asType(dEntity.class).getLivingEntity(), EquipmentSlot.valueOf(slot), new Element(split[2]).asType(dItem.class).getItemStack()); } else if (split.length > 2) { dB.echoError("'" + split[2] + "' is not a valid dItem!"); } } else if (split.length > 1) { dB.echoError("'" + split[1] + "' is not a valid slot; must be HAND, OFF_HAND, BOOTS, LEGS, CHEST, or HEAD!"); } else { NMSHandler.getInstance().getPacketHelper().resetEquipment(getPlayerEntity(), new Element(split[0]).asType(dEntity.class).getLivingEntity()); } } else { dB.echoError("'" + split[0] + "' is not a valid dEntity!"); } } } // <--[mechanism] // @object dPlayer // @name item_message // @input Element // @description // Shows the player an item message as if the item they are carrying had // changed names to the specified Element. // --> if (mechanism.matches("item_message")) { ItemChangeMessage.sendMessage(getPlayerEntity(), value.asString()); } // <--[mechanism] // @object dPlayer // @name show_endcredits // @input None // @description // Shows the player the end credits. // --> if (mechanism.matches("show_endcredits")) { NMSHandler.getInstance().getPlayerHelper().showEndCredits(getPlayerEntity()); } // <--[mechanism] // @object dPlayer // @name spectate // @input dEntity // @description // Forces the player to spectate from the entity's point of view. // Note: They cannot cancel the spectating without a re-log -- you // must make them spectate themselves to cancel the effect. // (i.e. - adjust <player> "spectate:<player>") // --> if (mechanism.matches("spectate") && mechanism.requireObject(dEntity.class)) { NMSHandler.getInstance().getPacketHelper().forceSpectate(getPlayerEntity(), value.asType(dEntity.class).getBukkitEntity()); } // <--[mechanism] // @object dPlayer // @name open_book // @input None // @description // Forces the player to open the written book in their hand. // The book can safely be removed from the player's hand // without the player closing the book. // --> if (mechanism.matches("open_book")) { NMSHandler.getInstance().getPacketHelper().openBook(getPlayerEntity(), EquipmentSlot.HAND); } // <--[mechanism] // @object dPlayer // @name open_offhand_book // @input None // @description // Forces the player to open the written book in their offhand. // The book can safely be removed from the player's offhand // without the player closing the book. // --> if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_9_R2) && mechanism.matches("open_offhand_book")) { NMSHandler.getInstance().getPacketHelper().openBook(getPlayerEntity(), EquipmentSlot.OFF_HAND); } // <--[mechanism] // @object dPlayer // @name edit_sign // @input dLocation // @description // Allows the player to edit an existing sign. To create a // sign, see <@link command Sign>. // --> if (mechanism.matches("edit_sign") && mechanism.requireObject(dLocation.class)) { if (!NMSHandler.getInstance().getPacketHelper().showSignEditor(getPlayerEntity(), value.asType(dLocation.class))) { dB.echoError("Can't edit non-sign materials!"); } } // <--[mechanism] // @object dPlayer // @name tab_list_info // @input Element(|Element) // @description // Show the player some text in the header and footer area // in their tab list. // - adjust <player> tab_list_info:<header>|<footer> // --> if (mechanism.matches("tab_list_info")) { if (!value.asString().isEmpty()) { String[] split = value.asString().split("[\\|" + dList.internal_escape + "]", 2); if (split.length > 0) { String header = split[0]; String footer = ""; if (split.length > 1) { footer = split[1]; } NMSHandler.getInstance().getPacketHelper().showTabListHeaderFooter(getPlayerEntity(), header, footer); } else { dB.echoError("Must specify a header and footer to show!"); } } else { NMSHandler.getInstance().getPacketHelper().resetTabListHeaderFooter(getPlayerEntity()); } } // <--[mechanism] // @object dPlayer // @name sign_update // @input dLocation|dList // @description // Shows the player fake lines on a sign. // --> if (mechanism.matches("sign_update")) { if (!value.asString().isEmpty()) { String[] split = value.asString().split("[\\|" + dList.internal_escape + "]", 2); if (dLocation.matches(split[0]) && split.length > 1) { dList lines = dList.valueOf(split[1]); getPlayerEntity().sendSignChange(dLocation.valueOf(split[0]), lines.toArray(4)); } else { dB.echoError("Must specify a valid location and at least one sign line!"); } } else { dB.echoError("Must specify a valid location and at least one sign line!"); } } // <--[mechanism] // @object dPlayer // @name banner_update // @input dLocation|Element(|dList) // @description // Shows the player a fake base color and, optionally, patterns on a banner. Input must be // in the form: "LOCATION|BASE_COLOR(|COLOR/PATTERN|...)" // For the list of possible colors, see <@link url http://bit.ly/1dydq12>. // For the list of possible patterns, see <@link url http://bit.ly/1MqRn7T>. // --> if (mechanism.matches("banner_update")) { if (value.asString().length() > 0) { String[] split = value.asString().split("[\\|" + dList.internal_escape + "]"); List<org.bukkit.block.banner.Pattern> patterns = new ArrayList<org.bukkit.block.banner.Pattern>(); if (split.length > 2) { List<String> splitList; for (int i = 2; i > split.length; i++) { String string = split[i]; try { splitList = CoreUtilities.split(string, '/', 2); patterns.add(new org.bukkit.block.banner.Pattern(DyeColor.valueOf(splitList.get(0).toUpperCase()), PatternType.valueOf(splitList.get(1).toUpperCase()))); } catch (Exception e) { dB.echoError("Could not apply pattern to banner: " + string); } } } if (dLocation.matches(split[0]) && split.length > 1) { dLocation location = dLocation.valueOf(split[0]); DyeColor base; try { base = DyeColor.valueOf(split[1].toUpperCase()); } catch (Exception e) { dB.echoError("Could not apply base color to banner: " + split[1]); return; } NMSHandler.getInstance().getPacketHelper().showBannerUpdate(getPlayerEntity(), location, base, patterns); } else { dB.echoError("Must specify a valid location and a base color!"); } } } // <--[mechanism] // @object dPlayer // @name action_bar // @input Element // @description // Sends the player text in the action bar. // --> if (mechanism.matches("action_bar")) { NMSHandler.getInstance().getPacketHelper().sendActionBarMessage(getPlayerEntity(), value.asString()); } // <--[mechanism] // @object dPlayer // @name name // @input Element // @description // Changes the name on this player's nameplate. // --> if (mechanism.matches("name")) { String name = value.asString(); if (name.length() > 16) { dB.echoError("Must specify a name with no more than 16 characters."); } else { NMSHandler.getInstance().getProfileEditor().setPlayerName(getPlayerEntity(), value.asString()); } } // <--[mechanism] // @object dPlayer // @name skin // @input Element // @description // Changes the skin of the player to the skin of the given // player name. // --> if (mechanism.matches("skin")) { String name = value.asString(); if (name.length() > 16) { dB.echoError("Must specify a name with no more than 16 characters."); } else { NMSHandler.getInstance().getProfileEditor().setPlayerSkin(getPlayerEntity(), value.asString()); } } // <--[mechanism] // @object dPlayer // @name skin_blob // @input Element // @description // Changes the skin of the player to the specified blob. // --> if (mechanism.matches("skin_blob")) { NMSHandler.getInstance().getProfileEditor().setPlayerSkinBlob(getPlayerEntity(), value.asString()); } // <--[mechanism] // @object dPlayer // @name is_whitelisted // @input Element(Boolean) // @description // Changes whether the player is whitelisted or not. // @tags // <p@player.is_whitelisted> // --> if (mechanism.matches("is_whitelisted") && mechanism.requireBoolean()) { getPlayerEntity().setWhitelisted(mechanism.getValue().asBoolean()); } // <--[mechanism] // @object dPlayer // @name is_op // @input Element(Boolean) // @description // Changes whether the player is a server operator or not. // @tags // <p@player.is_op> // --> if (mechanism.matches("is_op") && mechanism.requireBoolean()) { getOfflinePlayer().setOp(mechanism.getValue().asBoolean()); } // <--[mechanism] // @object dPlayer // @name is_banned // @input Element(Boolean) // @description // Set whether the player is banned or not. // @tags // <p@player.is_banned> // <p@player.ban_info.expiration> // <p@player.ban_info.reason> // <p@player.ban_info.created> // --> if (mechanism.matches("is_banned") && mechanism.requireBoolean()) { getOfflinePlayer().setBanned(mechanism.getValue().asBoolean()); } // <--[mechanism] // @object dPlayer // @name money // @input Element(Number) // @description // Set the amount of money a player has with the linked economy plugin. // (Only if supported by the registered Economy system.) // @tags // <p@player.money> // --> if (mechanism.matches("money") && mechanism.requireDouble() && Depends.economy != null) { double bal = Depends.economy.getBalance(getOfflinePlayer()); double goal = value.asDouble(); if (goal > bal) { Depends.economy.depositPlayer(getOfflinePlayer(), goal - bal); } else if (bal > goal) { Depends.economy.withdrawPlayer(getOfflinePlayer(), bal - goal); } } if (Depends.chat != null) { // <--[mechanism] // @object dPlayer // @name chat_prefix // @input Element // @description // Set the player's chat prefix. // @tags // <p@player.chat_prefix> // --> if (mechanism.matches("chat_prefix")) { Depends.chat.setPlayerPrefix(getPlayerEntity(), value.asString()); } // <--[mechanism] // @object dPlayer // @name chat_suffix // @input Element // @description // Set the player's chat suffix. // @tags // <p@player.chat_suffix> // --> if (mechanism.matches("chat_suffix")) { Depends.chat.setPlayerSuffix(getPlayerEntity(), value.asString()); } } // Iterate through this object's properties' mechanisms for (Property property : PropertyParser.getProperties(this)) { property.adjust(mechanism); if (mechanism.fulfilled()) { break; } } // Pass along to dEntity mechanism handler if not already handled. if (!mechanism.fulfilled()) { Adjustable entity = new dEntity(getPlayerEntity()); entity.adjust(mechanism); } } }