use of org.bukkit.util.RayTraceResult in project Denizen-For-Bukkit by DenizenScript.
the class PlayerTag method registerTags.
public static void registerTags() {
AbstractFlagTracker.registerFlagHandlers(tagProcessor);
// ///////////////////
// OFFLINE ATTRIBUTES
// ///////////////
// Defined in EntityTag
tagProcessor.registerTag(ElementTag.class, "is_player", (attribute, object) -> {
return new ElementTag(true);
});
// ///////////////////
// DENIZEN ATTRIBUTES
// ///////////////
// <--[tag]
// @attribute <PlayerTag.chat_history_list>
// @returns ListTag
// @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.
// -->
tagProcessor.registerTag(ListTag.class, "chat_history_list", (attribute, object) -> {
return new ListTag(PlayerTagBase.playerChatHistory.get(object.getUUID()), true);
});
// <--[tag]
// @attribute <PlayerTag.chat_history[(<#>)]>
// @returns ElementTag
// @description
// Returns the last thing the player said.
// If a number is specified, returns an earlier thing the player said.
// Works with offline players.
// -->
tagProcessor.registerTag(ElementTag.class, "chat_history", (attribute, object) -> {
int x = 1;
if (attribute.hasParam() && ArgumentHelper.matchesInteger(attribute.getParam())) {
x = attribute.getIntParam();
}
// No playerchathistory? Return null.
if (!PlayerTagBase.playerChatHistory.containsKey(object.getUUID())) {
return null;
}
List<String> messages = PlayerTagBase.playerChatHistory.get(object.getUUID());
if (messages.size() < x || x < 1) {
return null;
}
return new ElementTag(messages.get(x - 1), true);
});
// ///////////////////
// ECONOMY ATTRIBUTES
// ///////////////
// <--[tag]
// @attribute <PlayerTag.formatted_money>
// @returns ElementTag
// @plugin Vault
// @description
// Returns the formatted form of the player's money balance in the registered Economy system.
// -->
tagProcessor.registerTag(ElementTag.class, "formatted_money", (attribute, object) -> {
if (Depends.economy == null) {
if (!attribute.hasAlternative()) {
Debug.echoError("No economy loaded! Have you installed Vault and a compatible economy plugin?");
}
return null;
}
return new ElementTag(Depends.economy.format(Depends.economy.getBalance(object.getOfflinePlayer())), true);
});
// <--[tag]
// @attribute <PlayerTag.money>
// @returns ElementTag(Decimal)
// @plugin Vault
// @description
// Returns the amount of money the player has with the registered Economy system.
// May work offline depending on economy provider.
// -->
tagProcessor.registerTag(ElementTag.class, "money", (attribute, object) -> {
if (Depends.economy == null) {
if (!attribute.hasAlternative()) {
Debug.echoError("No economy loaded! Have you installed Vault and a compatible economy plugin?");
}
return null;
}
if (attribute.startsWith("formatted", 2)) {
attribute.fulfill(1);
Deprecations.playerMoneyFormatTag.warn(attribute.context);
return new ElementTag(Depends.economy.format(Depends.economy.getBalance(object.getOfflinePlayer())));
}
if (attribute.startsWith("currency_singular", 2)) {
attribute.fulfill(1);
Deprecations.oldEconomyTags.warn(attribute.context);
return new ElementTag(Depends.economy.currencyNameSingular());
}
if (attribute.startsWith("currency", 2)) {
attribute.fulfill(1);
Deprecations.oldEconomyTags.warn(attribute.context);
return new ElementTag(Depends.economy.currencyNamePlural());
}
return new ElementTag(Depends.economy.getBalance(object.getOfflinePlayer()));
});
// ///////////////////
// ENTITY LIST ATTRIBUTES
// ///////////////
// <--[tag]
// @attribute <PlayerTag.target[(<matcher>)]>
// @returns EntityTag
// @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 an entity type matcher to only count matches as possible targets.
// -->
registerOnlineOnlyTag(ObjectTag.class, "target", (attribute, object) -> {
double range = 50;
String matcher = attribute.hasParam() ? attribute.getParam() : null;
// -->
if (attribute.startsWith("within", 2) && attribute.hasContext(2)) {
range = attribute.getDoubleContext(2);
attribute.fulfill(1);
}
Location eyeLoc = object.getEyeLocation();
RayTraceResult result = eyeLoc.getWorld().rayTrace(eyeLoc, eyeLoc.getDirection(), range, FluidCollisionMode.NEVER, true, 0.01, (e) -> {
if (e.getUniqueId().equals(object.getUUID())) {
return false;
}
if (matcher != null) {
return BukkitScriptEvent.tryEntity(new EntityTag(e), matcher);
}
return true;
});
if (result == null || result.getHitEntity() == null) {
return null;
}
return new EntityTag(result.getHitEntity()).getDenizenObject();
});
// ///////////////////
// LOCATION ATTRIBUTES
// ///////////////
// <--[tag]
// @attribute <PlayerTag.bed_spawn>
// @returns LocationTag
// @mechanism PlayerTag.bed_spawn_location
// @description
// Returns the location of the player's bed spawn location, null if
// it doesn't exist.
// Works with offline players.
// -->
tagProcessor.registerTag(LocationTag.class, "bed_spawn", (attribute, object) -> {
try {
NMSHandler.getChunkHelper().changeChunkServerThread(object.getWorld());
if (object.getOfflinePlayer().getBedSpawnLocation() == null) {
return null;
}
return new LocationTag(object.getOfflinePlayer().getBedSpawnLocation());
} finally {
NMSHandler.getChunkHelper().restoreServerThread(object.getWorld());
}
});
tagProcessor.registerTag(ObjectTag.class, "location", (attribute, object) -> {
if (object.isOnline() && !object.getPlayerEntity().isDead()) {
return new EntityTag(object.getPlayerEntity()).doLocationTag(attribute);
}
return object.getLocation();
});
tagProcessor.registerTag(WorldTag.class, "world", (attribute, object) -> {
return new WorldTag(object.getWorld());
});
// ///////////////////
// STATE ATTRIBUTES
// ///////////////
// <--[tag]
// @attribute <PlayerTag.item_cooldown[<material>]>
// @returns DurationTag
// @description
// Returns the cooldown duration remaining on player's material.
// -->
registerOnlineOnlyTag(DurationTag.class, "item_cooldown", (attribute, object) -> {
MaterialTag mat = new ElementTag(attribute.getParam()).asType(MaterialTag.class, attribute.context);
if (mat != null) {
return new DurationTag((long) object.getPlayerEntity().getCooldown(mat.getMaterial()));
}
return null;
});
// <--[tag]
// @attribute <PlayerTag.first_played_time>
// @returns TimeTag
// @description
// Returns the time of when the player first logged on to this server.
// Works with offline players.
// -->
tagProcessor.registerTag(TimeTag.class, "first_played_time", (attribute, object) -> {
return new TimeTag(object.getOfflinePlayer().getFirstPlayed());
});
tagProcessor.registerTag(DurationTag.class, "first_played", (attribute, object) -> {
Deprecations.playerTimePlayedTags.warn(attribute.context);
return new DurationTag(object.getOfflinePlayer().getFirstPlayed() / 50);
});
// <--[tag]
// @attribute <PlayerTag.has_played_before>
// @returns ElementTag(Boolean)
// @description
// Returns whether the player has played before.
// Works with offline players.
// Note: This will just always return true.
// -->
tagProcessor.registerTag(ElementTag.class, "has_played_before", (attribute, object) -> {
return new ElementTag(true);
});
// <--[tag]
// @attribute <PlayerTag.exhaustion>
// @returns ElementTag(Decimal)
// @mechanism PlayerTag.exhaustion
// @description
// Returns the player's exhaustion value. Exhaustion is increased in vanilla when a player sprints or jumps, and is used to reduce food saturation over time.
// This can reach a maximum value of 40, and decreases by 4 every tick.
// Works with offline players.
// -->
tagProcessor.registerTag(ElementTag.class, "exhaustion", (attribute, object) -> {
if (object.isOnline()) {
return new ElementTag(object.getPlayerEntity().getExhaustion());
} else {
return new ElementTag(object.getNBTEditor().getExhaustion());
}
});
// Handle EntityTag oxygen tags here to allow getting them when the player is offline
tagProcessor.registerTag(DurationTag.class, "max_oxygen", (attribute, object) -> {
return new DurationTag((long) object.getMaximumAir());
});
tagProcessor.registerTag(DurationTag.class, "oxygen", (attribute, object) -> {
if (attribute.startsWith("max", 2)) {
Deprecations.entityMaxOxygenTag.warn(attribute.context);
attribute.fulfill(1);
return new DurationTag((long) object.getMaximumAir());
}
return new DurationTag((long) object.getRemainingAir());
});
// <--[tag]
// @attribute <PlayerTag.health_is_scaled>
// @returns ElementTag(Boolean)
// @description
// Returns whether the player's health bar is currently being scaled.
// -->
tagProcessor.registerTag(ElementTag.class, "health_is_scaled", (attribute, object) -> {
return new ElementTag(object.getPlayerEntity().isHealthScaled());
});
// <--[tag]
// @attribute <PlayerTag.health_scale>
// @returns ElementTag(Decimal)
// @mechanism PlayerTag.health_scale
// @description
// Returns the current scale for the player's health bar
// -->
tagProcessor.registerTag(ElementTag.class, "health_scale", (attribute, object) -> {
return new ElementTag(object.getPlayerEntity().getHealthScale());
});
// Handle EntityTag health tags here to allow getting them when the player is offline
tagProcessor.registerTag(ElementTag.class, "formatted_health", (attribute, object) -> {
Double maxHealth = attribute.hasParam() ? attribute.getDoubleParam() : null;
return EntityHealth.getHealthFormatted(new EntityTag(object.getPlayerEntity()), maxHealth);
});
tagProcessor.registerTag(ElementTag.class, "health_percentage", (attribute, object) -> {
double maxHealth = object.getPlayerEntity().getMaxHealth();
if (attribute.hasParam()) {
maxHealth = attribute.getIntParam();
}
return new ElementTag((object.getPlayerEntity().getHealth() / maxHealth) * 100);
});
tagProcessor.registerTag(ElementTag.class, "health_max", (attribute, object) -> {
return new ElementTag(object.getMaxHealth());
});
tagProcessor.registerTag(ElementTag.class, "health", (attribute, object) -> {
if (attribute.startsWith("is_scaled", 2)) {
attribute.fulfill(1);
Deprecations.entityHealthTags.warn(attribute.context);
return new ElementTag(object.getPlayerEntity().isHealthScaled());
}
if (attribute.startsWith("scale", 2)) {
attribute.fulfill(1);
Deprecations.entityHealthTags.warn(attribute.context);
return new ElementTag(object.getPlayerEntity().getHealthScale());
}
if (attribute.startsWith("formatted", 2)) {
Deprecations.entityHealthTags.warn(attribute.context);
Double maxHealth = attribute.hasContext(2) ? attribute.getDoubleContext(2) : null;
attribute.fulfill(1);
return EntityHealth.getHealthFormatted(new EntityTag(object.getPlayerEntity()), maxHealth);
}
if (attribute.startsWith("percentage", 2)) {
Deprecations.entityHealthTags.warn(attribute.context);
attribute.fulfill(1);
double maxHealth = object.getPlayerEntity().getMaxHealth();
if (attribute.hasParam()) {
maxHealth = attribute.getIntParam();
}
return new ElementTag((object.getPlayerEntity().getHealth() / maxHealth) * 100);
}
if (attribute.startsWith("max", 2)) {
Deprecations.entityHealthTags.warn(attribute.context);
attribute.fulfill(1);
return new ElementTag(object.getMaxHealth());
}
return new ElementTag(object.getHealth());
});
// <--[tag]
// @attribute <PlayerTag.is_banned>
// @returns ElementTag(Boolean)
// @description
// Returns whether the player is banned.
// -->
tagProcessor.registerTag(ElementTag.class, "is_banned", (attribute, object) -> {
BanEntry ban = Bukkit.getBanList(BanList.Type.NAME).getBanEntry(object.getName());
if (ban == null) {
return new ElementTag(false);
} else if (ban.getExpiration() == null) {
return new ElementTag(true);
}
return new ElementTag(ban.getExpiration().after(new Date()));
});
// <--[tag]
// @attribute <PlayerTag.is_online>
// @returns ElementTag(Boolean)
// @description
// Returns whether the player is currently online.
// Works with offline players (returns false in that case).
// -->
tagProcessor.registerTag(ElementTag.class, "is_online", (attribute, object) -> {
return new ElementTag(object.isOnline());
});
// <--[tag]
// @attribute <PlayerTag.is_op>
// @returns ElementTag(Boolean)
// @mechanism PlayerTag.is_op
// @description
// Returns whether the player is a full server operator.
// Works with offline players.
// -->
tagProcessor.registerTag(ElementTag.class, "is_op", (attribute, object) -> {
return new ElementTag(object.getOfflinePlayer().isOp());
});
// <--[tag]
// @attribute <PlayerTag.is_whitelisted>
// @returns ElementTag(Boolean)
// @mechanism PlayerTag.is_whitelisted
// @description
// Returns whether the player is whitelisted.
// Works with offline players.
// -->
tagProcessor.registerTag(ElementTag.class, "is_whitelisted", (attribute, object) -> {
return new ElementTag(object.getOfflinePlayer().isWhitelisted());
});
// <--[tag]
// @attribute <PlayerTag.last_played_time>
// @returns TimeTag
// @description
// Returns the time of when the player was last seen.
// Works with offline players.
// Not very useful for online players.
// -->
tagProcessor.registerTag(TimeTag.class, "last_played_time", (attribute, object) -> {
if (object.isOnline()) {
return TimeTag.now();
}
return new TimeTag(object.getOfflinePlayer().getLastPlayed());
});
tagProcessor.registerTag(DurationTag.class, "last_played", (attribute, object) -> {
Deprecations.playerTimePlayedTags.warn(attribute.context);
if (object.isOnline()) {
return new DurationTag(System.currentTimeMillis() / 50);
}
return new DurationTag(object.getOfflinePlayer().getLastPlayed() / 50);
});
// <--[tag]
// @attribute <PlayerTag.groups[(<world>)]>
// @returns ListTag
// @description
// Returns a list of all groups the player is in.
// May work with offline players, depending on permission plugin.
// -->
tagProcessor.registerTag(ListTag.class, "groups", (attribute, object) -> {
if (Depends.permissions == null) {
if (!attribute.hasAlternative()) {
Debug.echoError("No permission system loaded! Have you installed Vault and a compatible permissions plugin?");
}
return null;
}
ListTag list = new ListTag();
WorldTag world = null;
if (attribute.hasParam()) {
world = attribute.paramAsType(WorldTag.class);
if (world == null) {
Debug.echoError("Invalid world specified: " + attribute.getParam());
return null;
}
}
for (String group : Depends.permissions.getGroups()) {
if (Depends.permissions.playerInGroup(world != null ? world.getName() : null, object.getOfflinePlayer(), group)) {
list.addObject(new ElementTag(group, true));
}
}
return list;
});
// <--[tag]
// @attribute <PlayerTag.ban_expiration_time>
// @returns TimeTag
// @description
// Returns the expiration of the player's ban, if they are banned.
// Potentially can be null.
// -->
tagProcessor.registerTag(TimeTag.class, "ban_expiration_time", (attribute, object) -> {
BanEntry ban = Bukkit.getBanList(BanList.Type.NAME).getBanEntry(object.getName());
if (ban == null || ban.getExpiration() == null || (ban.getExpiration() != null && ban.getExpiration().before(new Date()))) {
return null;
}
return new TimeTag(ban.getExpiration().getTime());
});
tagProcessor.registerTag(DurationTag.class, "ban_expiration", (attribute, object) -> {
Deprecations.playerTimePlayedTags.warn(attribute.context);
BanEntry ban = Bukkit.getBanList(BanList.Type.NAME).getBanEntry(object.getName());
if (ban == null || ban.getExpiration() == null || (ban.getExpiration() != null && ban.getExpiration().before(new Date()))) {
return null;
}
return new DurationTag(ban.getExpiration().getTime() / 50);
});
// <--[tag]
// @attribute <PlayerTag.ban_reason>
// @returns ElementTag
// @description
// Returns the reason for the player's ban, if they are banned.
// -->
tagProcessor.registerTag(ElementTag.class, "ban_reason", (attribute, object) -> {
BanEntry ban = Bukkit.getBanList(BanList.Type.NAME).getBanEntry(object.getName());
if (ban == null || (ban.getExpiration() != null && ban.getExpiration().before(new Date()))) {
return null;
}
return new ElementTag(ban.getReason(), true);
});
// <--[tag]
// @attribute <PlayerTag.ban_created_time>
// @returns TimeTag
// @description
// Returns when the player's ban was created, if they are banned.
// -->
tagProcessor.registerTag(TimeTag.class, "ban_created_time", (attribute, object) -> {
BanEntry ban = Bukkit.getBanList(BanList.Type.NAME).getBanEntry(object.getName());
if (ban == null || (ban.getExpiration() != null && ban.getExpiration().before(new Date()))) {
return null;
}
return new TimeTag(ban.getCreated().getTime());
});
tagProcessor.registerTag(DurationTag.class, "ban_created", (attribute, object) -> {
Deprecations.timeTagRewrite.warn(attribute.context);
BanEntry ban = Bukkit.getBanList(BanList.Type.NAME).getBanEntry(object.getName());
if (ban == null || (ban.getExpiration() != null && ban.getExpiration().before(new Date()))) {
return null;
}
return new DurationTag(ban.getCreated().getTime() / 50);
});
// <--[tag]
// @attribute <PlayerTag.ban_source>
// @returns ElementTag
// @description
// Returns the source of the player's ban, if they are banned.
// -->
tagProcessor.registerTag(ElementTag.class, "ban_source", (attribute, object) -> {
BanEntry ban = Bukkit.getBanList(BanList.Type.NAME).getBanEntry(object.getName());
if (ban == null || (ban.getExpiration() != null && ban.getExpiration().before(new Date()))) {
return null;
}
return new ElementTag(ban.getSource(), true);
});
tagProcessor.registerTag(ObjectTag.class, "ban_info", (attribute, object) -> {
Deprecations.playerBanInfoTags.warn(attribute.context);
BanEntry ban = Bukkit.getBanList(BanList.Type.NAME).getBanEntry(object.getName());
if (ban == null || (ban.getExpiration() != null && ban.getExpiration().before(new Date()))) {
return null;
}
if (attribute.startsWith("expiration", 2) && ban.getExpiration() != null) {
attribute.fulfill(1);
return new DurationTag(ban.getExpiration().getTime() / 50);
} else if (attribute.startsWith("reason", 2)) {
attribute.fulfill(1);
return new ElementTag(ban.getReason());
} else if (attribute.startsWith("created", 2)) {
attribute.fulfill(1);
return new DurationTag(ban.getCreated().getTime() / 50);
} else if (attribute.startsWith("source", 2)) {
attribute.fulfill(1);
return new ElementTag(ban.getSource());
}
return null;
});
// <--[tag]
// @attribute <PlayerTag.in_group[<group_name>]>
// @returns ElementTag(Boolean)
// @description
// Returns whether the player is in the specified group.
// (May work with offline players, depending on your permissions system.)
// -->
tagProcessor.registerTag(ElementTag.class, "in_group", (attribute, object) -> {
if (Depends.permissions == null) {
if (!attribute.hasAlternative()) {
Debug.echoError("No permission system loaded! Have you installed Vault and a compatible permissions plugin?");
}
return null;
}
String group = attribute.getParam();
// Non-world specific permission
if (attribute.startsWith("global", 2)) {
attribute.fulfill(1);
return new ElementTag(Depends.permissions.playerInGroup(null, object.getOfflinePlayer(), group));
} else // Permission in certain world
if (attribute.startsWith("world", 2)) {
WorldTag world = null;
if (attribute.hasContext(2)) {
world = attribute.contextAsType(2, WorldTag.class);
if (world == null) {
Debug.echoError("Invalid world specified: " + attribute.getContext(2));
return null;
}
}
attribute.fulfill(1);
return new ElementTag(Depends.permissions.playerInGroup(world != null ? world.getName() : null, object.getOfflinePlayer(), group));
} else // Permission in current world
if (object.isOnline()) {
return new ElementTag(Depends.permissions.playerInGroup(object.getPlayerEntity(), group));
} else if (Depends.permissions != null) {
return new ElementTag(Depends.permissions.playerInGroup(null, object.getOfflinePlayer(), group));
}
return null;
});
// <--[tag]
// @attribute <PlayerTag.has_permission[permission.node]>
// @returns ElementTag(Boolean)
// @description
// Returns whether the player has the specified node.
// (May work with offline players, depending on your permissions system.)
// -->
tagProcessor.registerTag(ElementTag.class, "has_permission", (attribute, object) -> {
String permission = attribute.getParam();
// Non-world specific permission
if (attribute.startsWith("global", 2)) {
if (Depends.permissions == null) {
if (!attribute.hasAlternative()) {
Debug.echoError("No permission system loaded! Have you installed Vault and a compatible permissions plugin?");
}
return null;
}
attribute.fulfill(1);
return new ElementTag(Depends.permissions.playerHas(null, object.getOfflinePlayer(), permission));
} else // Permission in certain world
if (attribute.startsWith("world", 2)) {
String world = attribute.getContext(2);
if (Depends.permissions == null) {
if (!attribute.hasAlternative()) {
Debug.echoError("No permission system loaded! Have you installed Vault and a compatible permissions plugin?");
}
return null;
}
attribute.fulfill(1);
if (world.startsWith("w@")) {
world = world.substring(2);
}
return new ElementTag(Depends.permissions.playerHas(world, object.getOfflinePlayer(), permission));
} else // Permission in current world
if (object.isOnline()) {
return new ElementTag(object.getPlayerEntity().hasPermission(permission));
} else if (Depends.permissions != null) {
return new ElementTag(Depends.permissions.playerHas(null, object.getOfflinePlayer(), permission));
}
return null;
}, "permission");
// <--[tag]
// @attribute <PlayerTag.statistic[<statistic>]>
// @returns ElementTag(Number)
// @description
// Returns the player's current value for the specified statistic.
// Valid statistics: <@link url https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Statistic.html>
// Works with offline players.
// -->
tagProcessor.registerTag(ElementTag.class, "statistic", (attribute, object) -> {
if (!attribute.hasParam()) {
return null;
}
Statistic statistic;
try {
statistic = Statistic.valueOf(attribute.getParam().toUpperCase());
} catch (IllegalArgumentException ex) {
attribute.echoError("Statistic '" + attribute.getParam() + "' does not exist: " + ex.getMessage());
return null;
}
// -->
if (attribute.startsWith("qualifier", 2)) {
ObjectTag obj = ObjectFetcher.pickObjectFor(attribute.getContext(2), attribute.context);
attribute.fulfill(1);
try {
if (obj instanceof MaterialTag) {
return new ElementTag(object.getOfflinePlayer().getStatistic(statistic, ((MaterialTag) obj).getMaterial()));
} else if (obj instanceof EntityTag) {
return new ElementTag(object.getOfflinePlayer().getStatistic(statistic, ((EntityTag) obj).getBukkitEntityType()));
} else {
return null;
}
} catch (Exception e) {
Debug.echoError("Invalid statistic: " + statistic + " for this player!");
return null;
}
}
try {
return new ElementTag(object.getOfflinePlayer().getStatistic(statistic));
} catch (Exception e) {
Debug.echoError("Invalid statistic: " + statistic + " for this player!");
return null;
}
});
// <--[tag]
// @attribute <PlayerTag.uuid>
// @returns ElementTag
// @description
// Returns the UUID of the player.
// Works with offline players.
// -->
tagProcessor.registerTag(ElementTag.class, "uuid", (attribute, object) -> {
return new ElementTag(object.getUUID().toString());
});
// <--[tag]
// @attribute <PlayerTag.list_name>
// @returns ElementTag
// @mechanism PlayerTag.player_list_name
// @description
// Returns the name of the player as shown in the player list.
// -->
registerOnlineOnlyTag(ElementTag.class, "list_name", (attribute, object) -> {
return new ElementTag(AdvancedTextImpl.instance.getPlayerListName(object.getPlayerEntity()), true);
});
// <--[tag]
// @attribute <PlayerTag.display_name>
// @returns ElementTag
// @mechanism PlayerTag.display_name
// @description
// Returns the display name of the player, which may contain prefixes and suffixes, colors, etc.
// -->
registerOnlineOnlyTag(ElementTag.class, "display_name", (attribute, object) -> {
return new ElementTag(object.getPlayerEntity().getDisplayName(), true);
});
// Documented in EntityTag
tagProcessor.registerTag(ElementTag.class, "name", (attribute, object) -> {
if (attribute.startsWith("list", 2) && object.isOnline()) {
Deprecations.playerNameTags.warn(attribute.context);
attribute.fulfill(1);
return new ElementTag(object.getPlayerEntity().getPlayerListName(), true);
}
if (attribute.startsWith("display", 2) && object.isOnline()) {
Deprecations.playerNameTags.warn(attribute.context);
attribute.fulfill(1);
return new ElementTag(object.getPlayerEntity().getDisplayName(), true);
}
return new ElementTag(object.getName(), true);
});
// <--[tag]
// @attribute <PlayerTag.client_brand>
// @returns ElementTag
// @description
// Returns the brand of the client, as sent via the "minecraft:brand" packet.
// On normal clients, will say "vanilla". On broken clients, will say "unknown". Modded clients will identify themselves (though not guaranteed!).
// It may be ideal to change setting "Packets.Auto init" in the Denizen config to "true" to guarantee this tag functions as expected.
// -->
registerOnlineOnlyTag(ElementTag.class, "client_brand", (attribute, object) -> {
NetworkInterceptHelper.enable();
return new ElementTag(NMSHandler.getPlayerHelper().getPlayerBrand(object.getPlayerEntity()), true);
});
// <--[tag]
// @attribute <PlayerTag.locale>
// @returns ElementTag
// @description
// Returns the current locale of the player.
// -->
registerOnlineOnlyTag(ElementTag.class, "locale", (attribute, object) -> {
return new ElementTag(object.getPlayerEntity().getLocale(), true);
});
// ///////////////////
// INVENTORY ATTRIBUTES
// ///////////////
// <--[tag]
// @attribute <PlayerTag.inventory>
// @returns InventoryTag
// @description
// Returns a InventoryTag of the player's current inventory.
// Works with offline players.
// -->
tagProcessor.registerTag(InventoryTag.class, "inventory", (attribute, object) -> {
return object.getInventory();
});
// <--[tag]
// @attribute <PlayerTag.enderchest>
// @returns InventoryTag
// @description
// Gets the player's enderchest inventory.
// Works with offline players.
// -->
tagProcessor.registerTag(InventoryTag.class, "enderchest", (attribute, object) -> {
return object.getEnderChest();
});
// ///////////////////
// ONLINE ATTRIBUTES
// ///////////////
// <--[tag]
// @attribute <PlayerTag.open_inventory>
// @returns InventoryTag
// @description
// Gets the inventory the player currently has open. If the player has no open
// inventory, this returns the player's inventory.
// -->
registerOnlineOnlyTag(InventoryTag.class, "open_inventory", (attribute, object) -> {
return InventoryTag.mirrorBukkitInventory(object.getPlayerEntity().getOpenInventory().getTopInventory());
});
// <--[tag]
// @attribute <PlayerTag.discovered_recipes>
// @returns ListTag
// @description
// Returns a list of the recipes the player has discovered, in the Namespace:Key format, for example "minecraft:gold_nugget".
// -->
registerOnlineOnlyTag(ListTag.class, "discovered_recipes", (attribute, object) -> {
return new ListTag(NMSHandler.getEntityHelper().getDiscoveredRecipes(object.getPlayerEntity()));
});
// <--[tag]
// @attribute <PlayerTag.selected_trade_index>
// @returns ElementTag(Number)
// @description
// Returns the index of the trade the player is currently viewing, if any.
// -->
registerOnlineOnlyTag(ElementTag.class, "selected_trade_index", (attribute, object) -> {
if (object.getPlayerEntity().getOpenInventory().getTopInventory() instanceof MerchantInventory) {
return new ElementTag(((MerchantInventory) object.getPlayerEntity().getOpenInventory().getTopInventory()).getSelectedRecipeIndex() + 1);
}
return null;
});
// [tag]
// @attribute <PlayerTag.selected_trade>
// @returns TradeTag
// @description
// Returns the trade the player is currently viewing, if any.
// This is almost completely broke and only works if the player has placed items in the trade slots.
//
registerOnlineOnlyTag(TradeTag.class, "selected_trade", (attribute, object) -> {
Inventory playerInventory = object.getPlayerEntity().getOpenInventory().getTopInventory();
if (playerInventory instanceof MerchantInventory && ((MerchantInventory) playerInventory).getSelectedRecipe() != null) {
return new TradeTag(((MerchantInventory) playerInventory).getSelectedRecipe()).duplicate();
}
return null;
});
// <--[tag]
// @attribute <PlayerTag.item_on_cursor>
// @returns ItemTag
// @mechanism PlayerTag.item_on_cursor
// @description
// Returns the item on the player's cursor, if any. This includes
// chest interfaces, inventories, and hotbars, etc.
// -->
registerOnlineOnlyTag(ItemTag.class, "item_on_cursor", (attribute, object) -> {
return new ItemTag(object.getPlayerEntity().getItemOnCursor());
});
// <--[tag]
// @attribute <PlayerTag.held_item_slot>
// @returns ElementTag(Number)
// @description
// Returns the slot location of the player's selected item.
// -->
registerOnlineOnlyTag(ElementTag.class, "held_item_slot", (attribute, object) -> {
return new ElementTag(object.getPlayerEntity().getInventory().getHeldItemSlot() + 1);
});
registerOnlineOnlyTag(ObjectTag.class, "item_in_hand", (attribute, object) -> {
if (attribute.startsWith("slot", 2)) {
Deprecations.playerItemInHandSlotTag.warn(attribute.context);
attribute.fulfill(1);
return new ElementTag(object.getPlayerEntity().getInventory().getHeldItemSlot() + 1);
}
return object.getHeldItem();
});
// <--[tag]
// @attribute <PlayerTag.sidebar_lines>
// @returns ListTag
// @description
// Returns the current lines set on the player's Sidebar via <@link command sidebar>.
// -->
registerOnlineOnlyTag(ListTag.class, "sidebar_lines", (attribute, object) -> {
Sidebar sidebar = SidebarCommand.getSidebar(object);
if (sidebar == null) {
return null;
}
return new ListTag(sidebar.getLinesText(), true);
});
// <--[tag]
// @attribute <PlayerTag.sidebar_title>
// @returns ElementTag
// @description
// Returns the current title set on the player's Sidebar via <@link command sidebar>.
// -->
registerOnlineOnlyTag(ElementTag.class, "sidebar_title", (attribute, object) -> {
Sidebar sidebar = SidebarCommand.getSidebar(object);
if (sidebar == null) {
return null;
}
return new ElementTag(sidebar.getTitle(), true);
});
// <--[tag]
// @attribute <PlayerTag.sidebar_scores>
// @returns ListTag
// @description
// Returns the current scores set on the player's Sidebar via <@link command sidebar>,
// in the same order as <@link tag PlayerTag.sidebar_lines>.
// -->
registerOnlineOnlyTag(ListTag.class, "sidebar_scores", (attribute, object) -> {
Sidebar sidebar = SidebarCommand.getSidebar(object);
if (sidebar == null) {
return null;
}
ListTag scores = new ListTag();
for (int score : sidebar.getScores()) {
scores.add(String.valueOf(score));
}
return scores;
});
registerOnlineOnlyTag(ObjectTag.class, "sidebar", (attribute, object) -> {
Deprecations.playerSidebarTags.warn(attribute.context);
if (attribute.startsWith("lines", 2)) {
attribute.fulfill(1);
Sidebar sidebar = SidebarCommand.getSidebar(object);
if (sidebar == null) {
return null;
}
return new ListTag(sidebar.getLinesText());
}
if (attribute.startsWith("title", 2)) {
attribute.fulfill(1);
Sidebar sidebar = SidebarCommand.getSidebar(object);
if (sidebar == null) {
return null;
}
return new ElementTag(sidebar.getTitle());
}
if (attribute.startsWith("scores", 2)) {
attribute.fulfill(1);
Sidebar sidebar = SidebarCommand.getSidebar(object);
if (sidebar == null) {
return null;
}
ListTag scores = new ListTag();
for (int score : sidebar.getScores()) {
scores.add(String.valueOf(score));
}
return scores;
}
return null;
});
// <--[tag]
// @attribute <PlayerTag.skin_blob>
// @returns ElementTag
// @mechanism PlayerTag.skin_blob
// @description
// Returns the player's current skin blob.
// In the format: "texture;signature" (two values separated by a semicolon).
// See also <@link language Player Entity Skins (Skin Blobs)>.
// -->
registerOnlineOnlyTag(ElementTag.class, "skin_blob", (attribute, object) -> {
return new ElementTag(NMSHandler.getInstance().getProfileEditor().getPlayerSkinBlob(object.getPlayerEntity()));
});
// <--[tag]
// @attribute <PlayerTag.skull_skin>
// @returns ElementTag
// @description
// Returns the player's current skin blob, formatted for input to a Player Skull item.
// In the format: "UUID|Texture|Name" (three values separated by pipes).
// See also <@link language Player Entity Skins (Skin Blobs)>.
// -->
registerOnlineOnlyTag(ElementTag.class, "skull_skin", (attribute, object) -> {
String skin = NMSHandler.getInstance().getProfileEditor().getPlayerSkinBlob(object.getPlayerEntity());
if (skin == null) {
return null;
}
int semicolon = skin.indexOf(';');
return new ElementTag(object.getPlayerEntity().getUniqueId() + "|" + skin.substring(0, semicolon) + "|" + object.getName());
});
// <--[tag]
// @attribute <PlayerTag.skull_item>
// @returns ItemTag
// @description
// Returns a Player_Head item with the skin of the player.
// See also <@link language Player Entity Skins (Skin Blobs)>.
// -->
registerOnlineOnlyTag(ItemTag.class, "skull_item", (attribute, object) -> {
ItemStack item = new ItemStack(Material.PLAYER_HEAD);
item = NMSHandler.getItemHelper().setSkullSkin(item, NMSHandler.getInstance().getPlayerProfile(object.getPlayerEntity()));
return new ItemTag(item);
});
registerOnlineOnlyTag(ObjectTag.class, "attack_cooldown", (attribute, object) -> {
Deprecations.playerAttackCooldownTags.warn(attribute.context);
if (attribute.startsWith("duration", 2)) {
attribute.fulfill(1);
return new DurationTag((long) NMSHandler.getPlayerHelper().ticksPassedDuringCooldown(object.getPlayerEntity()));
} else if (attribute.startsWith("max_duration", 2)) {
attribute.fulfill(1);
return new DurationTag((long) NMSHandler.getPlayerHelper().getMaxAttackCooldownTicks(object.getPlayerEntity()));
} else if (attribute.startsWith("percent", 2)) {
attribute.fulfill(1);
return new ElementTag(NMSHandler.getPlayerHelper().getAttackCooldownPercent(object.getPlayerEntity()) * 100);
}
Debug.echoError("The tag 'player.attack_cooldown...' must be followed by a sub-tag.");
return null;
});
// <--[tag]
// @attribute <PlayerTag.main_hand>
// @returns ElementTag
// @description
// Returns the player's main hand, either LEFT or RIGHT.
// -->
registerOnlineOnlyTag(ElementTag.class, "main_hand", (attribute, object) -> {
return new ElementTag(object.getPlayerEntity().getMainHand().toString());
});
// ///////////////////
// CITIZENS ATTRIBUTES
// ///////////////
// <--[tag]
// @attribute <PlayerTag.selected_npc>
// @returns NPCTag
// @mechanism PlayerTag.selected_npc
// @description
// Returns the NPCTag that the player currently has selected with '/npc select', null if no NPC selected.
// -->
registerOnlineOnlyTag(NPCTag.class, "selected_npc", (attribute, object) -> {
if (object.getPlayerEntity().hasMetadata("selected")) {
return object.getSelectedNPC();
}
return null;
});
// ///////////////////
// CONVERSION ATTRIBUTES
// ///////////////
// <--[tag]
// @attribute <PlayerTag.entity>
// @returns EntityTag
// @description
// Returns the EntityTag object of the player.
// (Note: This should never actually be needed. PlayerTags are considered valid EntityTags.)
// -->
registerOnlineOnlyTag(EntityTag.class, "entity", (attribute, object) -> {
return new EntityTag(object.getPlayerEntity());
});
// ///////////////////
// IDENTIFICATION ATTRIBUTES
// ///////////////
// <--[tag]
// @attribute <PlayerTag.ip_address>
// @returns ElementTag
// @description
// Returns the player's IP address, without port or hostname.
// -->
registerOnlineOnlyTag(ElementTag.class, "ip_address", (attribute, object) -> {
return new ElementTag(object.getPlayerEntity().getAddress().getAddress().toString());
});
// <--[tag]
// @attribute <PlayerTag.ip>
// @returns ElementTag
// @description
// Returns the player's IP address host name.
// -->
registerOnlineOnlyTag(ElementTag.class, "ip", (attribute, object) -> {
// -->
if (attribute.startsWith("address_only", 2)) {
attribute.fulfill(1);
return new ElementTag(object.getPlayerEntity().getAddress().toString());
}
String host = object.getPlayerEntity().getAddress().getHostName();
// -->
if (attribute.startsWith("address", 2)) {
attribute.fulfill(1);
return new ElementTag(object.getPlayerEntity().getAddress().toString());
}
return new ElementTag(host);
}, "host_name");
// <--[tag]
// @attribute <PlayerTag.nameplate>
// @returns ElementTag
// @description
// Returns the displayed text in the nameplate of the player.
// -->
registerOnlineOnlyTag(ElementTag.class, "nameplate", (attribute, object) -> {
return new ElementTag(NMSHandler.getInstance().getProfileEditor().getPlayerName(object.getPlayerEntity()), true);
});
// ///////////////////
// LOCATION ATTRIBUTES
// ///////////////
// <--[tag]
// @attribute <PlayerTag.compass_target>
// @returns LocationTag
// @description
// Returns the location of the player's compass target.
// -->
registerOnlineOnlyTag(LocationTag.class, "compass_target", (attribute, object) -> {
Location target = object.getPlayerEntity().getCompassTarget();
if (target != null) {
return new LocationTag(target);
}
return null;
});
// <--[tag]
// @attribute <PlayerTag.chunk_loaded[<chunk>]>
// @returns ElementTag(Boolean)
// @description
// Returns whether the player has the chunk loaded on their client.
// -->
registerOnlineOnlyTag(ElementTag.class, "chunk_loaded", (attribute, object) -> {
if (!attribute.hasParam()) {
return null;
}
ChunkTag chunk = attribute.paramAsType(ChunkTag.class);
if (chunk == null) {
return null;
}
return new ElementTag(chunk.isLoadedSafe() && object.hasChunkLoaded(chunk.getChunkForTag(attribute)));
});
// ///////////////////
// STATE ATTRIBUTES
// ///////////////
// <--[tag]
// @attribute <PlayerTag.can_fly>
// @returns ElementTag(Boolean)
// @mechanism PlayerTag.can_fly
// @description
// Returns whether the player is allowed to fly.
// Works with offline players.
// -->
tagProcessor.registerTag(ElementTag.class, "can_fly", (attribute, object) -> {
if (object.isOnline()) {
return new ElementTag(object.getPlayerEntity().getAllowFlight());
} else {
return new ElementTag(object.getNBTEditor().getAllowFlight());
}
}, "allowed_flight");
// <--[tag]
// @attribute <PlayerTag.fly_speed>
// @returns ElementTag(Decimal)
// @mechanism PlayerTag.fly_speed
// @description
// Returns the speed the player can fly at.
// Default value is '0.2'.
// Works with offline players.
// -->
tagProcessor.registerTag(ElementTag.class, "fly_speed", (attribute, object) -> {
if (object.isOnline()) {
return new ElementTag(object.getPlayerEntity().getFlySpeed());
} else {
return new ElementTag(object.getNBTEditor().getFlySpeed());
}
});
// <--[tag]
// @attribute <PlayerTag.walk_speed>
// @returns ElementTag(Decimal)
// @mechanism PlayerTag.walk_speed
// @description
// Returns the speed the player can walk at.
// Works with offline players.
// -->
tagProcessor.registerTag(ElementTag.class, "walk_speed", (attribute, object) -> {
if (object.isOnline()) {
return new ElementTag(object.getPlayerEntity().getWalkSpeed());
} else {
return new ElementTag(object.getNBTEditor().getWalkSpeed());
}
});
// <--[tag]
// @attribute <PlayerTag.saturation>
// @returns ElementTag(Decimal)
// @mechanism PlayerTag.saturation
// @description
// Returns the current food saturation of the player.
// Works with offline players.
// -->
tagProcessor.registerTag(ElementTag.class, "saturation", (attribute, object) -> {
if (object.isOnline()) {
return new ElementTag(object.getPlayerEntity().getSaturation());
} else {
return new ElementTag(object.getNBTEditor().getSaturation());
}
});
// <--[tag]
// @attribute <PlayerTag.formatted_food_level[(<max>)]>
// @returns ElementTag
// @mechanism PlayerTag.food_level
// @description
// Returns a 'formatted' value of the player's current food level.
// May be 'starving', 'famished', 'parched, 'hungry', or 'healthy'.
// -->
registerOnlineOnlyTag(ElementTag.class, "formatted_food_level", (attribute, object) -> {
double maxHunger = object.getPlayerEntity().getMaxHealth();
if (attribute.hasParam()) {
maxHunger = attribute.getIntParam();
}
attribute.fulfill(1);
int foodLevel = object.getFoodLevel();
if (foodLevel / maxHunger < .10) {
return new ElementTag("starving");
} else if (foodLevel / maxHunger < .40) {
return new ElementTag("famished");
} else if (foodLevel / maxHunger < .75) {
return new ElementTag("parched");
} else if (foodLevel / maxHunger < 1) {
return new ElementTag("hungry");
} else {
return new ElementTag("healthy");
}
});
// <--[tag]
// @attribute <PlayerTag.food_level>
// @returns ElementTag(Number)
// @mechanism PlayerTag.food_level
// @description
// Returns the current food level (aka hunger) of the player.
// -->
registerOnlineOnlyTag(ElementTag.class, "food_level", (attribute, object) -> {
if (attribute.startsWith("formatted", 2)) {
Deprecations.playerFoodLevelFormatTag.warn(attribute.context);
double maxHunger = object.getPlayerEntity().getMaxHealth();
if (attribute.hasContext(2)) {
maxHunger = attribute.getIntContext(2);
}
attribute.fulfill(1);
int foodLevel = object.getFoodLevel();
if (foodLevel / maxHunger < .10) {
return new ElementTag("starving");
} else if (foodLevel / maxHunger < .40) {
return new ElementTag("famished");
} else if (foodLevel / maxHunger < .75) {
return new ElementTag("parched");
} else if (foodLevel / maxHunger < 1) {
return new ElementTag("hungry");
} else {
return new ElementTag("healthy");
}
}
return new ElementTag(object.getFoodLevel());
});
// <--[tag]
// @attribute <PlayerTag.gamemode>
// @returns ElementTag
// @mechanism PlayerTag.gamemode
// @description
// Returns the name of the gamemode the player is currently set to.
// Works with offline players.
// -->
tagProcessor.registerTag(ElementTag.class, "gamemode", (attribute, object) -> {
if (object.isOnline()) {
return new ElementTag(object.getPlayerEntity().getGameMode().name());
}
return new ElementTag(object.getNBTEditor().getGameMode().name());
});
// <--[tag]
// @attribute <PlayerTag.is_blocking>
// @returns ElementTag(Boolean)
// @description
// Returns whether the player is currently blocking.
// -->
registerOnlineOnlyTag(ElementTag.class, "is_blocking", (attribute, object) -> {
return new ElementTag(object.getPlayerEntity().isBlocking());
});
// <--[tag]
// @attribute <PlayerTag.ping>
// @returns ElementTag(Number)
// @description
// Returns the player's current ping.
// -->
registerOnlineOnlyTag(ElementTag.class, "ping", (attribute, object) -> {
return new ElementTag(NMSHandler.getPlayerHelper().getPing(object.getPlayerEntity()));
});
// <--[tag]
// @attribute <PlayerTag.is_flying>
// @returns ElementTag(Boolean)
// @description
// Returns whether the player is currently flying.
// -->
registerOnlineOnlyTag(ElementTag.class, "is_flying", (attribute, object) -> {
return new ElementTag(object.getPlayerEntity().isFlying());
});
// <--[tag]
// @attribute <PlayerTag.is_sneaking>
// @returns ElementTag(Boolean)
// @description
// Returns whether the player is currently sneaking.
// -->
registerOnlineOnlyTag(ElementTag.class, "is_sneaking", (attribute, object) -> {
return new ElementTag(object.getPlayerEntity().isSneaking());
});
// <--[tag]
// @attribute <PlayerTag.is_sprinting>
// @returns ElementTag(Boolean)
// @mechanism PlayerTag.sprinting
// @description
// Returns whether the player is currently sprinting.
// -->
registerOnlineOnlyTag(ElementTag.class, "is_sprinting", (attribute, object) -> {
return new ElementTag(object.getPlayerEntity().isSprinting());
});
// <--[tag]
// @attribute <PlayerTag.has_advancement[<advancement>]>
// @returns ElementTag(Boolean)
// @description
// Returns whether the player has completed the specified advancement.
// -->
registerOnlineOnlyTag(ElementTag.class, "has_advancement", (attribute, object) -> {
if (!attribute.hasParam()) {
return null;
}
Advancement adv = AdvancementHelper.getAdvancement(attribute.getParam());
if (adv == null) {
if (!attribute.hasAlternative()) {
Debug.echoError("Advancement '" + attribute.getParam() + "' does not exist.");
}
return null;
}
AdvancementProgress progress = object.getPlayerEntity().getAdvancementProgress(adv);
return new ElementTag(progress.isDone());
});
// <--[tag]
// @attribute <PlayerTag.advancements>
// @returns ListTag
// @description
// Returns a list of the names of all advancements the player has completed.
// -->
registerOnlineOnlyTag(ListTag.class, "advancements", (attribute, object) -> {
ListTag list = new ListTag();
Bukkit.advancementIterator().forEachRemaining((adv) -> {
if (object.getPlayerEntity().getAdvancementProgress(adv).isDone()) {
list.add(adv.getKey().toString());
}
});
return list;
}, "list_advancements");
// <--[tag]
// @attribute <PlayerTag.time_asleep>
// @returns DurationTag
// @description
// Returns the time the player has been asleep.
// -->
registerOnlineOnlyTag(DurationTag.class, "time_asleep", (attribute, object) -> {
return new DurationTag((long) object.getPlayerEntity().getSleepTicks());
});
// <--[tag]
// @attribute <PlayerTag.time>
// @returns ElementTag(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 <@link command time> is being used on the player.
// -->
registerOnlineOnlyTag(ElementTag.class, "time", (attribute, object) -> {
return new ElementTag(object.getPlayerEntity().getPlayerTime());
});
// <--[tag]
// @attribute <PlayerTag.weather>
// @returns ElementTag
// @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.
// -->
registerOnlineOnlyTag(ElementTag.class, "weather", (attribute, object) -> {
if (object.getPlayerEntity().getPlayerWeather() != null) {
return new ElementTag(object.getPlayerEntity().getPlayerWeather().name());
} else {
return null;
}
});
// <--[tag]
// @attribute <PlayerTag.calculate_xp>
// @returns ElementTag(Number)
// @description
// Returns the calculated total amount of XP the player has, based on the amount of experience needed per level, for each level the player has.
// -->
registerOnlineOnlyTag(ElementTag.class, "calculate_xp", (attribute, object) -> {
int level = object.getPlayerEntity().getLevel();
return new ElementTag(ExperienceCommand.TOTAL_XP_FOR_LEVEL(level) + (object.getPlayerEntity().getExp() * ExperienceCommand.XP_FOR_NEXT_LEVEL(level)));
});
// <--[tag]
// @attribute <PlayerTag.xp_level>
// @returns ElementTag(Number)
// @description
// Returns the number of XP levels the player has.
// -->
registerOnlineOnlyTag(ElementTag.class, "xp_level", (attribute, object) -> {
return new ElementTag(object.getPlayerEntity().getLevel());
});
// <--[tag]
// @attribute <PlayerTag.xp_to_next_level>
// @returns ElementTag(Number)
// @description
// Returns the amount of XP the player needs to get to the next level.
// -->
registerOnlineOnlyTag(ElementTag.class, "xp_to_next_level", (attribute, object) -> {
return new ElementTag(object.getPlayerEntity().getExpToLevel());
});
// <--[tag]
// @attribute <PlayerTag.xp_total>
// @returns ElementTag(Number)
// @description
// Returns the total amount of experience points the player has.
// This is how much XP the player has ever received, not a current value.
// To get the current total, use @<link tag PlayerTag.calculate_xp>.
// -->
registerOnlineOnlyTag(ElementTag.class, "xp_total", (attribute, object) -> {
return new ElementTag(object.getPlayerEntity().getTotalExperience());
});
// <--[tag]
// @attribute <PlayerTag.xp>
// @returns ElementTag(Decimal)
// @description
// Returns the percentage of experience points to the next level.
// -->
registerOnlineOnlyTag(ElementTag.class, "xp", (attribute, object) -> {
if (attribute.startsWith("level", 2)) {
Deprecations.playerXpTags.warn(attribute.context);
attribute.fulfill(1);
return new ElementTag(object.getPlayerEntity().getLevel());
}
if (attribute.startsWith("to_next_level", 2)) {
Deprecations.playerXpTags.warn(attribute.context);
attribute.fulfill(1);
return new ElementTag(object.getPlayerEntity().getExpToLevel());
}
if (attribute.startsWith("total", 2)) {
Deprecations.playerXpTags.warn(attribute.context);
attribute.fulfill(1);
return new ElementTag(object.getPlayerEntity().getTotalExperience());
}
return new ElementTag(object.getPlayerEntity().getExp() * 100);
});
// <--[tag]
// @attribute <PlayerTag.chat_prefix>
// @returns ElementTag
// @plugin Vault
// @mechanism PlayerTag.chat_prefix
// @description
// Returns the player's chat prefix.
// NOTE: May work with offline players.
// Requires a Vault-compatible chat plugin.
// -->
tagProcessor.registerTag(ElementTag.class, "chat_prefix", (attribute, object) -> {
if (Depends.chat == null) {
if (!attribute.hasAlternative()) {
Debug.echoError("'chat_prefix' tag unavailable: Vault and a chat plugin are required.");
}
return null;
}
String prefix = Depends.chat.getPlayerPrefix(object.getWorld().getName(), object.getOfflinePlayer());
if (prefix == null) {
return null;
}
return new ElementTag(prefix, true);
});
// <--[tag]
// @attribute <PlayerTag.chat_suffix>
// @returns ElementTag
// @plugin Vault
// @mechanism PlayerTag.chat_suffix
// @description
// Returns the player's chat suffix.
// NOTE: May work with offline players.
// Requires a Vault-compatible chat plugin.
// -->
tagProcessor.registerTag(ElementTag.class, "chat_suffix", (attribute, object) -> {
if (Depends.chat == null) {
if (!attribute.hasAlternative()) {
Debug.echoError("'chat_suffix' tag unavailable: Vault and a chat plugin are required.");
}
return null;
}
String suffix = Depends.chat.getPlayerSuffix(object.getWorld().getName(), object.getOfflinePlayer());
if (suffix == null) {
return null;
}
return new ElementTag(suffix, true);
});
// <--[tag]
// @attribute <PlayerTag.fake_block_locations>
// @returns ListTag(LocationTag)
// @description
// Returns a list of locations that the player will see a fake block at, as set by <@link command showfake> or connected commands.
// -->
tagProcessor.registerTag(ListTag.class, "fake_block_locations", (attribute, object) -> {
ListTag list = new ListTag();
FakeBlock.FakeBlockMap map = FakeBlock.blocks.get(object.getUUID());
if (map != null) {
for (LocationTag loc : map.byLocation.keySet()) {
list.addObject(loc.clone());
}
}
return list;
});
// <--[tag]
// @attribute <PlayerTag.fake_block[<location>]>
// @returns MaterialTag
// @description
// Returns the fake material that the player will see at the input location, as set by <@link command showfake> or connected commands.
// Works best alongside <@link tag PlayerTag.fake_block_locations>.
// Returns null if the player doesn't have a fake block at the location.
// -->
tagProcessor.registerTag(MaterialTag.class, "fake_block", (attribute, object) -> {
if (!attribute.hasParam()) {
return null;
}
LocationTag input = attribute.paramAsType(LocationTag.class);
FakeBlock.FakeBlockMap map = FakeBlock.blocks.get(object.getUUID());
if (map != null) {
FakeBlock block = map.byLocation.get(input);
if (block != null) {
return block.material;
}
}
return null;
});
// <--[tag]
// @attribute <PlayerTag.fake_entities>
// @returns ListTag(EntityTag)
// @description
// Returns a list of fake entities the player can see, as set by <@link command fakespawn>.
// Note that these entities are not being tracked by the server, so many operations may not be possible on them.
// -->
tagProcessor.registerTag(ListTag.class, "fake_entities", (attribute, object) -> {
ListTag list = new ListTag();
FakeEntity.FakeEntityMap map = FakeEntity.playersToEntities.get(object.getUUID());
if (map != null) {
for (Map.Entry<Integer, FakeEntity> entry : map.byId.entrySet()) {
list.addObject(entry.getValue().entity);
}
}
return list;
});
// <--[tag]
// @attribute <PlayerTag.disguise_to_self[(<player>)]>
// @returns EntityTag
// @group properties
// @description
// Returns the fake entity used to disguise the entity in the player's self-view (only relevant to players), either globally (if no context input given), or to the specified player.
// Relates to <@link command disguise>.
// -->
tagProcessor.registerTag(EntityTag.class, "disguise_to_self", (attribute, object) -> {
HashMap<UUID, DisguiseCommand.TrackedDisguise> map = DisguiseCommand.disguises.get(object.getUUID());
if (map == null) {
return null;
}
DisguiseCommand.TrackedDisguise disguise;
if (attribute.hasParam()) {
PlayerTag player = attribute.paramAsType(PlayerTag.class);
if (player == null) {
attribute.echoError("Invalid player for is_disguised tag.");
return null;
}
disguise = map.get(player.getUUID());
if (disguise == null) {
disguise = map.get(null);
}
} else {
disguise = map.get(null);
}
if (disguise == null) {
return null;
}
if (disguise.fakeToSelf == null) {
return null;
}
return disguise.fakeToSelf.entity;
});
// <--[tag]
// @attribute <PlayerTag.spectator_target>
// @returns EntityTag
// @mechanism PlayerTag.spectator_target
// @description
// Returns the entity that a spectator-mode player is currently spectating, if any.
// -->
registerOnlineOnlyTag(ObjectTag.class, "spectator_target", (attribute, object) -> {
if (object.getPlayerEntity().getGameMode() != GameMode.SPECTATOR) {
return null;
}
Entity target = object.getPlayerEntity().getSpectatorTarget();
if (target == null) {
return null;
}
return new EntityTag(target).getDenizenObject();
});
// <--[tag]
// @attribute <PlayerTag.packets_sent>
// @returns ElementTag(Number)
// @description
// Returns a total count of how many network packets have been sent to this player while they have been online.
// It may be ideal to change setting "Packets.Auto init" in the Denizen config to "true" to guarantee this tag functions as expected.
// -->
registerOnlineOnlyTag(ElementTag.class, "packets_sent", (attribute, object) -> {
NetworkInterceptHelper.enable();
return new ElementTag(NMSHandler.getPacketHelper().getPacketStats(object.getPlayerEntity(), true));
});
// <--[tag]
// @attribute <PlayerTag.packets_received>
// @returns ElementTag(Number)
// @description
// Returns a total count of how many network packets have been received from this player while they have been online.
// It may be ideal to change setting "Packets.Auto init" in the Denizen config to "true" to guarantee this tag functions as expected.
// -->
registerOnlineOnlyTag(ElementTag.class, "packets_received", (attribute, object) -> {
NetworkInterceptHelper.enable();
return new ElementTag(NMSHandler.getPacketHelper().getPacketStats(object.getPlayerEntity(), false));
});
// <--[tag]
// @attribute <PlayerTag.fish_hook>
// @returns EntityTag
// @description
// Returns the fishing hook a player has cast (if any).
// -->
registerOnlineOnlyTag(EntityTag.class, "fish_hook", (attribute, object) -> {
FishHook hook = NMSHandler.getFishingHelper().getHookFrom(object.getPlayerEntity());
if (hook == null) {
return null;
}
return new EntityTag(hook);
});
// <--[tag]
// @attribute <PlayerTag.spawn_forced>
// @returns ElementTag(Boolean)
// @mechanism PlayerTag.spawn_forced
// @description
// Returns whether the player's bed spawn location is forced (ie still valid even if a bed is missing).
// -->
tagProcessor.registerTag(ElementTag.class, "spawn_forced", (attribute, object) -> {
if (object.isOnline()) {
return new ElementTag(NMSHandler.getPlayerHelper().getSpawnForced(object.getPlayerEntity()));
}
return new ElementTag(object.getNBTEditor().isSpawnForced());
});
// <--[tag]
// @attribute <PlayerTag.last_action_time>
// @returns TimeTag
// @description
// Returns the time of the last direct input from the player. Internally used with <@link tag server.idle_timeout>.
// -->
registerOnlineOnlyTag(TimeTag.class, "last_action_time", (attribute, object) -> {
// The internal time values use monotonic time - this converts to real time.
long playerMilliTime = NMSHandler.getPlayerHelper().getLastActionTime(object.getPlayerEntity());
long relativeMillis = System.nanoTime() / 1000000L - playerMilliTime;
return new TimeTag(System.currentTimeMillis() - relativeMillis);
});
// <--[tag]
// @attribute <PlayerTag.scoreboard_id>
// @returns ElementTag
// @description
// Returns the ID of the scoreboard from <@link command scoreboard> that a player is currently viewing, if any.
// -->
tagProcessor.registerTag(ElementTag.class, "scoreboard_id", (attribute, object) -> {
String id = ScoreboardHelper.viewerMap.get(object.getUUID());
if (id == null) {
return null;
}
return new ElementTag(id);
});
// <--[tag]
// @attribute <PlayerTag.bossbar_ids>
// @returns ListTag
// @description
// Returns a list of all bossbars from <@link command bossbar> that this player can see.
// Does not list bossbars created by any other source.
// -->
registerOnlineOnlyTag(ListTag.class, "bossbar_ids", (attribute, object) -> {
ListTag result = new ListTag();
for (Map.Entry<String, BossBar> bar : BossBarCommand.bossBarMap.entrySet()) {
if (bar.getValue().getPlayers().contains(object.getPlayerEntity())) {
result.addObject(new ElementTag(bar.getKey(), true));
}
}
return result;
});
// <--[tag]
// @attribute <PlayerTag.tab_completions[<command>]>
// @returns ListTag
// @description
// Returns a list of all tab completions for the given plaintext of a command.
// Input is formatted equivalent to if it were typed into a chat bar, minus the '/' slash at the start.
// Input must necessarily contain at least one space.
// For example: "<player.tab_completions[npc ]>" will return all /NPC sub command names available to the player.
// This is only compatible with commands registered in Spigot. Meaning in particular, vanilla commands are not recognized or supported.
// -->
registerOnlineOnlyTag(ListTag.class, "tab_completions", (attribute, object) -> {
if (!attribute.hasParam()) {
return null;
}
String cmdFull = attribute.getParam();
int space = cmdFull.indexOf(' ');
if (space == -1) {
attribute.echoError("Invalid command input '" + cmdFull + "': must have at least one space");
return null;
}
String cmdName = cmdFull.substring(0, space);
PluginCommand actualCmd = Bukkit.getPluginCommand(cmdName);
if (actualCmd == null) {
attribute.echoError("Unknown command '" + cmdName + "'");
return null;
}
String args = cmdFull.substring(space + 1);
ListTag result = new ListTag();
for (String str : actualCmd.tabComplete(object.getPlayerEntity(), cmdName, CoreUtilities.split(args, ' ').toArray(new String[0]))) {
result.addObject(new ElementTag(str, true));
}
return result;
});
}
use of org.bukkit.util.RayTraceResult in project Denizen-For-Bukkit by DenizenScript.
the class EntityTag method registerTags.
public static void registerTags() {
AbstractFlagTracker.registerFlagHandlers(tagProcessor);
PropertyParser.registerPropertyTagHandlers(EntityTag.class, tagProcessor);
// ///////////////////
// UNSPAWNED ATTRIBUTES
// ///////////////
// <--[tag]
// @attribute <EntityTag.entity_type>
// @returns ElementTag
// @group data
// @description
// Returns the type of the entity.
// -->
tagProcessor.registerTag(ElementTag.class, "entity_type", (attribute, object) -> {
return new ElementTag(object.entity_type.getName());
});
// <--[tag]
// @attribute <EntityTag.translated_name>
// @returns ElementTag
// @description
// Returns the localized name of the entity.
// Note that this is a magic Denizen tool - refer to <@link language Denizen Text Formatting>.
// -->
tagProcessor.registerTag(ElementTag.class, "translated_name", (attribute, object) -> {
String key = object.getEntityType().getBukkitEntityType().getKey().getKey();
return new ElementTag(ChatColor.COLOR_CHAR + "[translate=entity.minecraft." + key + "]");
});
// <--[tag]
// @attribute <EntityTag.is_spawned>
// @returns ElementTag(Boolean)
// @group data
// @description
// Returns whether the entity is spawned.
// -->
tagProcessor.registerTag(ElementTag.class, "is_spawned", (attribute, object) -> {
return new ElementTag(object.isSpawned());
});
// <--[tag]
// @attribute <EntityTag.eid>
// @returns ElementTag(Number)
// @group data
// @description
// Returns the entity's temporary server entity ID.
// -->
registerSpawnedOnlyTag(ElementTag.class, "eid", (attribute, object) -> {
return new ElementTag(object.getBukkitEntity().getEntityId());
});
// <--[tag]
// @attribute <EntityTag.uuid>
// @returns ElementTag
// @group data
// @description
// Returns the permanent unique ID of the entity.
// Works with offline players.
// -->
tagProcessor.registerTag(ElementTag.class, "uuid", (attribute, object) -> {
return new ElementTag(object.getUUID().toString());
});
// <--[tag]
// @attribute <EntityTag.script>
// @returns ScriptTag
// @group data
// @description
// Returns the entity script that spawned this entity, if any.
// -->
tagProcessor.registerTag(ScriptTag.class, "script", (attribute, object) -> {
if (object.entityScript == null) {
return null;
}
ScriptTag tag = new ScriptTag(object.entityScript);
if (tag.isValid()) {
return tag;
}
return null;
});
// <--[tag]
// @attribute <EntityTag.scriptname>
// @returns ElementTag
// @deprecated use ".script.name" instead.
// @group data
// @description
// Use ".script.name" instead.
// -->
tagProcessor.registerTag(ElementTag.class, "scriptname", (attribute, object) -> {
Deprecations.hasScriptTags.warn(attribute.context);
if (object.entityScript == null) {
return null;
}
return new ElementTag(object.entityScript);
});
// ///////////////////
// IDENTIFICATION ATTRIBUTES
// ///////////////
registerSpawnedOnlyTag(ObjectTag.class, "custom_id", (attribute, object) -> {
Deprecations.entityCustomIdTag.warn(attribute.context);
if (CustomNBT.hasCustomNBT(object.getLivingEntity(), "denizen-script-id")) {
return new ScriptTag(CustomNBT.getCustomNBT(object.getLivingEntity(), "denizen-script-id"));
} else {
return new ElementTag(object.getBukkitEntity().getType().name());
}
});
// <--[tag]
// @attribute <EntityTag.name>
// @returns ElementTag
// @group data
// @description
// Returns the name of the entity.
// This can be a player name, an NPC name, a custom_name, or the entity type.
// Works with offline players.
// -->
registerSpawnedOnlyTag(ElementTag.class, "name", (attribute, object) -> {
return new ElementTag(object.getName(), true);
});
// ///////////////////
// INVENTORY ATTRIBUTES
// ///////////////
// <--[tag]
// @attribute <EntityTag.saddle>
// @returns ItemTag
// @group inventory
// @description
// If the entity is a horse or pig, returns the saddle as a ItemTag, or air if none.
// -->
registerSpawnedOnlyTag(ItemTag.class, "saddle", (attribute, object) -> {
if (object.getLivingEntity() instanceof AbstractHorse) {
return new ItemTag(((AbstractHorse) object.getLivingEntity()).getInventory().getSaddle());
} else if (object.getLivingEntity() instanceof Steerable) {
return new ItemTag(((Steerable) object.getLivingEntity()).hasSaddle() ? Material.SADDLE : Material.AIR);
}
return null;
});
// <--[tag]
// @attribute <EntityTag.horse_armor>
// @returns ItemTag
// @group inventory
// @description
// If the entity is a horse, returns the item equipped as the horses armor, or air if none.
// -->
registerSpawnedOnlyTag(ItemTag.class, "horse_armor", (attribute, object) -> {
if (object.getLivingEntity() instanceof Horse) {
return new ItemTag(((Horse) object.getLivingEntity()).getInventory().getArmor());
}
return null;
}, "horse_armour");
// <--[tag]
// @attribute <EntityTag.has_saddle>
// @returns ElementTag(Boolean)
// @group inventory
// @description
// If the entity is a pig or horse, returns whether it has a saddle equipped.
// -->
registerSpawnedOnlyTag(ElementTag.class, "has_saddle", (attribute, object) -> {
if (object.getLivingEntity() instanceof AbstractHorse) {
return new ElementTag(((AbstractHorse) object.getLivingEntity()).getInventory().getSaddle().getType() == Material.SADDLE);
} else if (object.getLivingEntity() instanceof Steerable) {
return new ElementTag(((Steerable) object.getLivingEntity()).hasSaddle());
}
return null;
});
// <--[tag]
// @attribute <EntityTag.is_trading>
// @returns ElementTag(Boolean)
// @description
// Returns whether the villager entity is trading.
// -->
registerSpawnedOnlyTag(ElementTag.class, "is_trading", (attribute, object) -> {
if (object.getBukkitEntity() instanceof Merchant) {
return new ElementTag(((Merchant) object.getBukkitEntity()).isTrading());
}
return null;
});
// <--[tag]
// @attribute <EntityTag.trading_with>
// @returns PlayerTag
// @description
// Returns the player who is trading with the villager entity, or null if it is not trading.
// -->
registerSpawnedOnlyTag(EntityFormObject.class, "trading_with", (attribute, object) -> {
if (object.getBukkitEntity() instanceof Merchant && ((Merchant) object.getBukkitEntity()).getTrader() != null) {
return new EntityTag(((Merchant) object.getBukkitEntity()).getTrader()).getDenizenObject();
}
return null;
});
// ///////////////////
// LOCATION ATTRIBUTES
// ///////////////
// <--[tag]
// @attribute <EntityTag.map_trace>
// @returns LocationTag
// @group location
// @description
// Returns a 2D location indicating where on the map the entity's looking at.
// Each coordinate is in the range of 0 to 128.
// -->
registerSpawnedOnlyTag(LocationTag.class, "map_trace", (attribute, object) -> {
EntityHelper.MapTraceResult mtr = NMSHandler.getEntityHelper().mapTrace(object.getLivingEntity(), 200);
if (mtr != null) {
double x = 0;
double y;
double basex = mtr.hitLocation.getX() - Math.floor(mtr.hitLocation.getX());
double basey = mtr.hitLocation.getY() - Math.floor(mtr.hitLocation.getY());
double basez = mtr.hitLocation.getZ() - Math.floor(mtr.hitLocation.getZ());
if (mtr.angle == BlockFace.NORTH) {
x = 128f - (basex * 128f);
} else if (mtr.angle == BlockFace.SOUTH) {
x = basex * 128f;
} else if (mtr.angle == BlockFace.WEST) {
x = basez * 128f;
} else if (mtr.angle == BlockFace.EAST) {
x = 128f - (basez * 128f);
}
y = 128f - (basey * 128f);
return new LocationTag(null, Math.round(x), Math.round(y));
}
return null;
});
// <--[tag]
// @attribute <EntityTag.can_see[<entity>]>
// @returns ElementTag(Boolean)
// @group location
// @description
// Returns whether the entity can see the specified other entity (has an uninterrupted line-of-sight).
// -->
registerSpawnedOnlyTag(ElementTag.class, "can_see", (attribute, object) -> {
if (object.isLivingEntity() && attribute.hasParam() && EntityTag.matches(attribute.getParam())) {
EntityTag toEntity = attribute.paramAsType(EntityTag.class);
if (toEntity != null && toEntity.isSpawnedOrValidForTag()) {
return new ElementTag(object.getLivingEntity().hasLineOfSight(toEntity.getBukkitEntity()));
}
}
return null;
});
// <--[tag]
// @attribute <EntityTag.eye_location>
// @returns LocationTag
// @group location
// @description
// Returns the location of the entity's eyes.
// -->
registerSpawnedOnlyTag(LocationTag.class, "eye_location", (attribute, object) -> {
return new LocationTag(object.getEyeLocation());
});
// <--[tag]
// @attribute <EntityTag.eye_height>
// @returns ElementTag(Number)
// @group location
// @description
// Returns the height of the entity's eyes above its location.
// -->
registerSpawnedOnlyTag(ElementTag.class, "eye_height", (attribute, object) -> {
if (object.isLivingEntity()) {
return new ElementTag(object.getLivingEntity().getEyeHeight());
}
return null;
});
// <--[tag]
// @attribute <EntityTag.cursor_on_solid[(<range>)]>
// @returns LocationTag
// @group location
// @description
// Returns the location of the solid block the entity is looking at.
// Optionally, specify a maximum range to find the location from (defaults to 200).
// This uses logic equivalent to <@link tag LocationTag.precise_cursor_on_block[(range)]>.
// Note that this will return null if there is no solid block in range.
// This only uses solid blocks, ie it ignores passable blocks like tall-grass. Use <@link tag EntityTag.cursor_on> to include passable blocks.
// -->
registerSpawnedOnlyTag(LocationTag.class, "cursor_on_solid", (attribute, object) -> {
double range = attribute.getDoubleParam();
if (range <= 0) {
range = 200;
}
RayTraceResult traced = object.getWorld().rayTraceBlocks(object.getEyeLocation(), object.getEyeLocation().getDirection(), range, FluidCollisionMode.NEVER, true);
if (traced != null && traced.getHitBlock() != null) {
return new LocationTag(traced.getHitBlock().getLocation());
}
return null;
});
// <--[tag]
// @attribute <EntityTag.cursor_on[(<range>)]>
// @returns LocationTag
// @group location
// @description
// Returns the location of the block the entity is looking at.
// Optionally, specify a maximum range to find the location from (defaults to 200).
// This uses logic equivalent to <@link tag LocationTag.precise_cursor_on_block[(range)]>.
// Note that this will return null if there is no block in range.
// This uses all blocks, ie it includes passable blocks like tall-grass and water. Use <@link tag EntityTag.cursor_on_solid> to exclude passable blocks.
// -->
registerSpawnedOnlyTag(LocationTag.class, "cursor_on", (attribute, object) -> {
double range = attribute.getDoubleParam();
if (range <= 0) {
range = 200;
}
RayTraceResult traced = object.getWorld().rayTraceBlocks(object.getEyeLocation(), object.getEyeLocation().getDirection(), range, FluidCollisionMode.ALWAYS, false);
if (traced != null && traced.getHitBlock() != null) {
return new LocationTag(traced.getHitBlock().getLocation());
}
return null;
});
// <--[tag]
// @attribute <EntityTag.location>
// @returns LocationTag
// @group location
// @description
// Returns the location of the entity.
// For living entities, this is at the center of their feet.
// For eye location, use <@link tag EntityTag.eye_location>
// Works with offline players.
// -->
registerSpawnedOnlyTag(LocationTag.class, "location", (attribute, object) -> {
return object.doLocationTag(attribute);
});
// <--[tag]
// @attribute <EntityTag.standing_on>
// @returns LocationTag
// @group location
// @description
// Returns the location of the block the entity is standing on top of (if on the ground, returns null if in the air).
// -->
registerSpawnedOnlyTag(LocationTag.class, "standing_on", (attribute, object) -> {
if (!object.getBukkitEntity().isOnGround()) {
return null;
}
Location loc = object.getBukkitEntity().getLocation().clone().subtract(0, 0.05f, 0);
return new LocationTag(loc.getWorld(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
});
// <--[tag]
// @attribute <EntityTag.body_yaw>
// @returns ElementTag(Decimal)
// @group location
// @description
// Returns the entity's body yaw (separate from head yaw).
// -->
registerSpawnedOnlyTag(ElementTag.class, "body_yaw", (attribute, object) -> {
return new ElementTag(NMSHandler.getEntityHelper().getBaseYaw(object.getBukkitEntity()));
});
// <--[tag]
// @attribute <EntityTag.velocity>
// @returns LocationTag
// @group location
// @mechanism EntityTag.velocity
// @description
// Returns the movement velocity of the entity.
// Note: Does not accurately calculate player clientside movement velocity.
// -->
registerSpawnedOnlyTag(LocationTag.class, "velocity", (attribute, object) -> {
return new LocationTag(object.getBukkitEntity().getVelocity().toLocation(object.getBukkitEntity().getWorld()));
});
// <--[tag]
// @attribute <EntityTag.world>
// @returns WorldTag
// @group location
// @description
// Returns the world the entity is in. Works with offline players.
// -->
registerSpawnedOnlyTag(WorldTag.class, "world", (attribute, object) -> {
return new WorldTag(object.getBukkitEntity().getWorld());
});
// ///////////////////
// STATE ATTRIBUTES
// ///////////////
// <--[tag]
// @attribute <EntityTag.can_pickup_items>
// @returns ElementTag(Boolean)
// @mechanism EntityTag.can_pickup_items
// @group attributes
// @description
// Returns whether the entity can pick up items.
// -->
registerSpawnedOnlyTag(ElementTag.class, "can_pickup_items", (attribute, object) -> {
if (object.isLivingEntity()) {
return new ElementTag(object.getLivingEntity().getCanPickupItems());
}
return null;
});
// <--[tag]
// @attribute <EntityTag.fallingblock_material>
// @returns MaterialTag
// @mechanism EntityTag.fallingblock_type
// @group attributes
// @description
// Returns the material of a fallingblock-type entity.
// -->
registerSpawnedOnlyTag(MaterialTag.class, "fallingblock_material", (attribute, object) -> {
if (!(object.getBukkitEntity() instanceof FallingBlock)) {
return null;
}
return new MaterialTag(((FallingBlock) object.getBukkitEntity()).getBlockData());
});
// <--[tag]
// @attribute <EntityTag.fall_distance>
// @returns ElementTag(Decimal)
// @mechanism EntityTag.fall_distance
// @group attributes
// @description
// Returns how far the entity has fallen.
// -->
registerSpawnedOnlyTag(ElementTag.class, "fall_distance", (attribute, object) -> {
return new ElementTag(object.getBukkitEntity().getFallDistance());
});
// <--[tag]
// @attribute <EntityTag.fire_time>
// @returns DurationTag
// @mechanism EntityTag.fire_time
// @group attributes
// @description
// Returns the duration for which the entity will remain on fire
// -->
registerSpawnedOnlyTag(DurationTag.class, "fire_time", (attribute, object) -> {
return new DurationTag(object.getBukkitEntity().getFireTicks() / 20);
});
// <--[tag]
// @attribute <EntityTag.on_fire>
// @returns ElementTag(Boolean)
// @group attributes
// @description
// Returns whether the entity is currently ablaze or not.
// -->
registerSpawnedOnlyTag(ElementTag.class, "on_fire", (attribute, object) -> {
return new ElementTag(object.getBukkitEntity().getFireTicks() > 0);
});
// <--[tag]
// @attribute <EntityTag.leash_holder>
// @returns EntityTag
// @mechanism EntityTag.leash_holder
// @group attributes
// @description
// Returns the leash holder of entity.
// -->
registerSpawnedOnlyTag(EntityFormObject.class, "leash_holder", (attribute, object) -> {
if (object.isLivingEntity() && object.getLivingEntity().isLeashed()) {
return new EntityTag(object.getLivingEntity().getLeashHolder()).getDenizenObject();
}
return null;
}, "get_leash_holder");
// <--[tag]
// @attribute <EntityTag.passengers>
// @returns ListTag(EntityTag)
// @mechanism EntityTag.passengers
// @group attributes
// @description
// Returns a list of the entity's passengers, if any.
// -->
registerSpawnedOnlyTag(ListTag.class, "passengers", (attribute, object) -> {
ArrayList<EntityTag> passengers = new ArrayList<>();
for (Entity ent : object.getBukkitEntity().getPassengers()) {
passengers.add(new EntityTag(ent));
}
return new ListTag(passengers);
}, "get_passengers");
// <--[tag]
// @attribute <EntityTag.passenger>
// @returns EntityTag
// @mechanism EntityTag.passenger
// @group attributes
// @description
// Returns the entity's passenger, if any.
// -->
registerSpawnedOnlyTag(EntityFormObject.class, "passenger", (attribute, object) -> {
if (!object.getBukkitEntity().isEmpty()) {
return new EntityTag(object.getBukkitEntity().getPassenger()).getDenizenObject();
}
return null;
}, "get_passenger");
// <--[tag]
// @attribute <EntityTag.shooter>
// @returns EntityTag
// @group attributes
// @mechanism EntityTag.shooter
// @synonyms EntityTag.arrow_firer,EntityTag.fishhook_shooter,EntityTag.snowball_thrower
// @description
// Returns the projectile's shooter, if any.
// -->
registerSpawnedOnlyTag(EntityFormObject.class, "shooter", (attribute, object) -> {
EntityTag shooter = object.getShooter();
if (shooter == null) {
return null;
}
return shooter.getDenizenObject();
}, "get_shooter");
// <--[tag]
// @attribute <EntityTag.left_shoulder>
// @returns EntityTag
// @mechanism EntityTag.left_shoulder
// @description
// Returns the entity on the entity's left shoulder.
// Only applies to player-typed entities.
// NOTE: The returned entity will not be spawned within the world,
// so most operations are invalid unless the entity is first spawned in.
// -->
registerSpawnedOnlyTag(EntityFormObject.class, "left_shoulder", (attribute, object) -> {
if (!(object.getLivingEntity() instanceof HumanEntity)) {
return null;
}
Entity e = ((HumanEntity) object.getLivingEntity()).getShoulderEntityLeft();
if (e == null) {
return null;
}
return new EntityTag(e).getDenizenObject();
});
// <--[tag]
// @attribute <EntityTag.right_shoulder>
// @returns EntityTag
// @mechanism EntityTag.right_shoulder
// @description
// Returns the entity on the entity's right shoulder.
// Only applies to player-typed entities.
// NOTE: The returned entity will not be spawned within the world,
// so most operations are invalid unless the entity is first spawned in.
// -->
registerSpawnedOnlyTag(EntityFormObject.class, "right_shoulder", (attribute, object) -> {
if (!(object.getLivingEntity() instanceof HumanEntity)) {
return null;
}
Entity e = ((HumanEntity) object.getLivingEntity()).getShoulderEntityRight();
if (e == null) {
return null;
}
return new EntityTag(e).getDenizenObject();
});
// <--[tag]
// @attribute <EntityTag.vehicle>
// @returns EntityTag
// @group attributes
// @description
// If the entity is in a vehicle, returns the vehicle as a EntityTag.
// -->
registerSpawnedOnlyTag(EntityFormObject.class, "vehicle", (attribute, object) -> {
if (object.getBukkitEntity().isInsideVehicle()) {
return new EntityTag(object.getBukkitEntity().getVehicle()).getDenizenObject();
}
return null;
}, "get_vehicle");
// <--[tag]
// @attribute <EntityTag.can_breed>
// @returns ElementTag(Boolean)
// @mechanism EntityTag.can_breed
// @group attributes
// @description
// Returns whether the animal entity is capable of mating with another of its kind.
// -->
registerSpawnedOnlyTag(ElementTag.class, "can_breed", (attribute, object) -> {
if (!(object.getLivingEntity() instanceof Breedable)) {
return new ElementTag(false);
}
return new ElementTag(((Breedable) object.getLivingEntity()).canBreed());
});
// <--[tag]
// @attribute <EntityTag.breeding>
// @returns ElementTag(Boolean)
// @mechanism EntityTag.breed
// @group attributes
// @description
// Returns whether the animal entity is trying to with another of its kind.
// -->
registerSpawnedOnlyTag(ElementTag.class, "breeding", (attribute, object) -> {
if (!(object.getLivingEntity() instanceof Animals)) {
return null;
}
return new ElementTag(((Animals) object.getLivingEntity()).getLoveModeTicks() > 0);
}, "is_breeding");
// <--[tag]
// @attribute <EntityTag.has_passenger>
// @returns ElementTag(Boolean)
// @mechanism EntityTag.passenger
// @group attributes
// @description
// Returns whether the entity has a passenger.
// -->
registerSpawnedOnlyTag(ElementTag.class, "has_passenger", (attribute, object) -> {
return new ElementTag(!object.getBukkitEntity().isEmpty());
});
// <--[tag]
// @attribute <EntityTag.is_empty>
// @returns ElementTag(Boolean)
// @group attributes
// @description
// Returns whether the entity does not have a passenger.
// -->
registerSpawnedOnlyTag(ElementTag.class, "is_empty", (attribute, object) -> {
return new ElementTag(object.getBukkitEntity().isEmpty());
}, "empty");
// <--[tag]
// @attribute <EntityTag.is_inside_vehicle>
// @returns ElementTag(Boolean)
// @group attributes
// @description
// Returns whether the entity is inside a vehicle.
// -->
registerSpawnedOnlyTag(ElementTag.class, "is_inside_vehicle", (attribute, object) -> {
return new ElementTag(object.getBukkitEntity().isInsideVehicle());
}, "inside_vehicle");
// <--[tag]
// @attribute <EntityTag.is_leashed>
// @returns ElementTag(Boolean)
// @group attributes
// @description
// Returns whether the entity is leashed.
// -->
registerSpawnedOnlyTag(ElementTag.class, "is_leashed", (attribute, object) -> {
return new ElementTag(object.isLivingEntity() && object.getLivingEntity().isLeashed());
}, "leashed");
// <--[tag]
// @attribute <EntityTag.is_sheared>
// @returns ElementTag(Boolean)
// @group attributes
// @description
// Returns whether a sheep is sheared.
// -->
registerSpawnedOnlyTag(ElementTag.class, "is_sheared", (attribute, object) -> {
if (!(object.getBukkitEntity() instanceof Sheep)) {
return null;
}
return new ElementTag(((Sheep) object.getBukkitEntity()).isSheared());
});
// <--[tag]
// @attribute <EntityTag.is_on_ground>
// @returns ElementTag(Boolean)
// @group attributes
// @description
// Returns whether the entity is supported by a block.
// This can be inaccurate for players.
// -->
registerSpawnedOnlyTag(ElementTag.class, "is_on_ground", (attribute, object) -> {
return new ElementTag(object.getBukkitEntity().isOnGround());
}, "on_ground");
// <--[tag]
// @attribute <EntityTag.is_persistent>
// @returns ElementTag(Boolean)
// @group attributes
// @mechanism EntityTag.persistent
// @description
// Returns whether the entity will not be removed completely when far away from players.
// In other words: whether the entity should be saved to file when chunks unload (otherwise, the entity is gone entirely if despawned for any reason).
// -->
// <--[tag]
// @attribute <EntityTag.persistent>
// @returns ElementTag(Boolean)
// @group attributes
// @mechanism EntityTag.persistent
// @deprecated use 'is_persistent'
// @description
// Outdated form of <@link tag EntityTag.is_persistent>
// -->
registerSpawnedOnlyTag(ElementTag.class, "is_persistent", (attribute, object) -> {
return new ElementTag(object.isLivingEntity() && !object.getLivingEntity().getRemoveWhenFarAway());
}, "persistent");
// <--[tag]
// @attribute <EntityTag.is_collidable>
// @returns ElementTag(Boolean)
// @mechanism EntityTag.collidable
// @group attributes
// @description
// Returns whether the entity is collidable.
// Returns the persistent collidable value for NPCs.
// -->
registerSpawnedOnlyTag(ElementTag.class, "is_collidable", (attribute, object) -> {
if (object.isCitizensNPC()) {
return new ElementTag(object.getDenizenNPC().getCitizen().data().get(NPC.COLLIDABLE_METADATA, true));
}
return new ElementTag(object.getLivingEntity().isCollidable());
});
// <--[tag]
// @attribute <EntityTag.is_sleeping>
// @returns ElementTag(Boolean)
// @description
// Returns whether the player, NPC, or villager is currently sleeping.
// -->
registerSpawnedOnlyTag(ElementTag.class, "is_sleeping", (attribute, object) -> {
if (object.getBukkitEntity() instanceof Player) {
return new ElementTag(((Player) object.getBukkitEntity()).isSleeping());
} else if (object.getBukkitEntity() instanceof Villager) {
return new ElementTag(((Villager) object.getBukkitEntity()).isSleeping());
}
return null;
});
// <--[tag]
// @attribute <EntityTag.killer>
// @returns PlayerTag
// @group attributes
// @description
// Returns the player that last killed the entity.
// -->
registerSpawnedOnlyTag(PlayerTag.class, "killer", (attribute, object) -> {
return getPlayerFrom(object.getLivingEntity().getKiller());
});
registerSpawnedOnlyTag(ObjectTag.class, "last_damage", (attribute, object) -> {
// -->
if (attribute.startsWith("amount", 2)) {
attribute.fulfill(1);
return new ElementTag(object.getLivingEntity().getLastDamage());
}
// -->
if (attribute.startsWith("cause", 2)) {
attribute.fulfill(1);
if (object.getBukkitEntity().getLastDamageCause() == null) {
return null;
}
return new ElementTag(object.getBukkitEntity().getLastDamageCause().getCause().name());
}
// -->
if (attribute.startsWith("duration", 2)) {
attribute.fulfill(1);
return new DurationTag((long) object.getLivingEntity().getNoDamageTicks());
}
// -->
if (attribute.startsWith("max_duration", 2)) {
attribute.fulfill(1);
return new DurationTag((long) object.getLivingEntity().getMaximumNoDamageTicks());
}
return null;
});
// <--[tag]
// @attribute <EntityTag.absorption_health>
// @returns ElementTag(Decimal)
// @mechanism EntityTag.absorption_health
// @description
// Returns the living entity's absorption health.
// -->
registerSpawnedOnlyTag(ElementTag.class, "absorption_health", (attribute, object) -> {
return new ElementTag(NMSHandler.getEntityHelper().getAbsorption(object.getLivingEntity()));
});
// <--[tag]
// @attribute <EntityTag.max_oxygen>
// @returns DurationTag
// @group attributes
// @description
// Returns the maximum duration of oxygen the entity can have.
// Works with offline players.
// -->
registerSpawnedOnlyTag(DurationTag.class, "max_oxygen", (attribute, object) -> {
return new DurationTag((long) object.getLivingEntity().getMaximumAir());
});
// <--[tag]
// @attribute <EntityTag.oxygen>
// @returns DurationTag
// @mechanism EntityTag.oxygen
// @group attributes
// @description
// Returns the duration of oxygen the entity has left.
// Works with offline players.
// -->
registerSpawnedOnlyTag(DurationTag.class, "oxygen", (attribute, object) -> {
if (attribute.startsWith("max", 2)) {
Deprecations.entityMaxOxygenTag.warn(attribute.context);
attribute.fulfill(1);
return new DurationTag((long) object.getLivingEntity().getMaximumAir());
}
return new DurationTag((long) object.getLivingEntity().getRemainingAir());
});
registerSpawnedOnlyTag(ElementTag.class, "remove_when_far", (attribute, object) -> {
Deprecations.entityRemoveWhenFar.warn(attribute.context);
return new ElementTag(object.getLivingEntity().getRemoveWhenFarAway());
});
// <--[tag]
// @attribute <EntityTag.target>
// @returns EntityTag
// @group attributes
// @description
// Returns the target entity of the creature or shulker_bullet, if any.
// This is the entity that a hostile mob is currently trying to attack.
// -->
registerSpawnedOnlyTag(EntityFormObject.class, "target", (attribute, object) -> {
if (object.getBukkitEntity() instanceof Creature) {
Entity target = ((Creature) object.getLivingEntity()).getTarget();
if (target != null) {
return new EntityTag(target).getDenizenObject();
}
} else if (object.getBukkitEntity() instanceof ShulkerBullet) {
Entity target = ((ShulkerBullet) object.getLivingEntity()).getTarget();
if (target != null) {
return new EntityTag(target).getDenizenObject();
}
}
return null;
});
// <--[tag]
// @attribute <EntityTag.precise_target[(<range>)]>
// @returns EntityTag
// @description
// Returns the entity this entity is looking at, using precise ray trace logic.
// Optionally, specify a maximum range to find the entity from (defaults to 200).
// -->
registerSpawnedOnlyTag(EntityFormObject.class, "precise_target", (attribute, object) -> {
int range = attribute.getIntParam();
if (range < 1) {
range = 200;
}
Predicate<Entity> requirement;
// -->
if (attribute.startsWith("type", 2) && attribute.hasContext(2)) {
attribute.fulfill(1);
String matcher = attribute.getParam();
requirement = (e) -> !e.equals(object.getBukkitEntity()) && BukkitScriptEvent.tryEntity(new EntityTag(e), matcher);
} else {
requirement = (e) -> !e.equals(object.getBukkitEntity());
}
RayTraceResult result = object.getWorld().rayTrace(object.getEyeLocation(), object.getEyeLocation().getDirection(), range, FluidCollisionMode.NEVER, true, 0, requirement);
if (result != null && result.getHitEntity() != null) {
return new EntityTag(result.getHitEntity()).getDenizenObject();
}
return null;
});
// <--[tag]
// @attribute <EntityTag.precise_target_position[(<range>)]>
// @returns LocationTag
// @description
// Returns the location this entity is looking at, using precise ray trace (against entities) logic.
// Optionally, specify a maximum range to find the target from (defaults to 200).
// -->
registerSpawnedOnlyTag(LocationTag.class, "precise_target_position", (attribute, object) -> {
int range = attribute.getIntParam();
if (range < 1) {
range = 200;
}
Predicate<Entity> requirement;
// -->
if (attribute.startsWith("type", 2) && attribute.hasContext(2)) {
attribute.fulfill(1);
String matcher = attribute.getParam();
requirement = (e) -> !e.equals(object.getBukkitEntity()) && BukkitScriptEvent.tryEntity(new EntityTag(e), matcher);
} else {
requirement = (e) -> !e.equals(object.getBukkitEntity());
}
RayTraceResult result = object.getWorld().rayTrace(object.getEyeLocation(), object.getEyeLocation().getDirection(), range, FluidCollisionMode.NEVER, true, 0, requirement);
if (result != null) {
return new LocationTag(object.getWorld(), result.getHitPosition());
}
return null;
});
// <--[tag]
// @attribute <EntityTag.time_lived>
// @returns DurationTag
// @mechanism EntityTag.time_lived
// @group attributes
// @description
// Returns how long the entity has lived.
// -->
registerSpawnedOnlyTag(DurationTag.class, "time_lived", (attribute, object) -> {
return new DurationTag(object.getBukkitEntity().getTicksLived() / 20);
});
// <--[tag]
// @attribute <EntityTag.pickup_delay>
// @returns DurationTag
// @mechanism EntityTag.pickup_delay
// @group attributes
// @description
// Returns how long before the item-type entity can be picked up by a player.
// -->
registerSpawnedOnlyTag(DurationTag.class, "pickup_delay", (attribute, object) -> {
if (!(object.getBukkitEntity() instanceof Item)) {
return null;
}
return new DurationTag(((Item) object.getBukkitEntity()).getPickupDelay() * 20);
}, "pickupdelay");
// <--[tag]
// @attribute <EntityTag.is_in_block>
// @returns ElementTag(Boolean)
// @group attributes
// @description
// Returns whether or not the arrow/trident entity is in a block.
// -->
registerSpawnedOnlyTag(ElementTag.class, "is_in_block", (attribute, object) -> {
if (object.getBukkitEntity() instanceof Arrow) {
return new ElementTag(((Arrow) object.getBukkitEntity()).isInBlock());
}
return null;
});
// <--[tag]
// @attribute <EntityTag.attached_block>
// @returns LocationTag
// @group attributes
// @description
// Returns the location of the block that the arrow/trident or hanging entity is attached to.
// -->
registerSpawnedOnlyTag(LocationTag.class, "attached_block", (attribute, object) -> {
if (object.getBukkitEntity() instanceof Arrow) {
Block attachedBlock = ((Arrow) object.getBukkitEntity()).getAttachedBlock();
if (attachedBlock != null) {
return new LocationTag(attachedBlock.getLocation());
}
} else if (object.getBukkitEntity() instanceof Hanging) {
Vector dir = ((Hanging) object.getBukkitEntity()).getAttachedFace().getDirection();
return new LocationTag(object.getLocation().clone().add(dir.multiply(0.5))).getBlockLocation();
}
return null;
});
// <--[tag]
// @attribute <EntityTag.gliding>
// @returns ElementTag(Boolean)
// @mechanism EntityTag.gliding
// @group attributes
// @description
// Returns whether this entity is gliding.
// -->
registerSpawnedOnlyTag(ElementTag.class, "gliding", (attribute, object) -> {
return new ElementTag(object.getLivingEntity().isGliding());
});
// <--[tag]
// @attribute <EntityTag.swimming>
// @returns ElementTag(Boolean)
// @mechanism EntityTag.swimming
// @group attributes
// @description
// Returns whether this entity is swimming.
// -->
registerSpawnedOnlyTag(ElementTag.class, "swimming", (attribute, object) -> {
return new ElementTag(object.getLivingEntity().isSwimming());
});
// <--[tag]
// @attribute <EntityTag.visual_pose>
// @returns ElementTag
// @group attributes
// @description
// Returns the name of the entity's current visual pose.
// See <@link url https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/entity/Pose.html>
// -->
registerSpawnedOnlyTag(ElementTag.class, "visual_pose", (attribute, object) -> {
return new ElementTag(object.getBukkitEntity().getPose().name());
});
// <--[tag]
// @attribute <EntityTag.glowing>
// @returns ElementTag(Boolean)
// @mechanism EntityTag.glowing
// @group attributes
// @description
// Returns whether this entity is glowing.
// -->
registerSpawnedOnlyTag(ElementTag.class, "glowing", (attribute, object) -> {
return new ElementTag(object.getBukkitEntity().isGlowing());
});
// ///////////////////
// TYPE ATTRIBUTES
// ///////////////
// <--[tag]
// @attribute <EntityTag.is_living>
// @returns ElementTag(Boolean)
// @group data
// @description
// Returns whether the entity type is a living-type entity (eg a cow or a player or anything else that lives, as specifically opposed to non-living entities like paintings, etc).
// Not to be confused with the idea of being alive - see <@link tag EntityTag.is_spawned>.
// -->
tagProcessor.registerTag(ElementTag.class, "is_living", (attribute, object) -> {
return new ElementTag(object.isLivingEntityType());
});
// <--[tag]
// @attribute <EntityTag.is_monster>
// @returns ElementTag(Boolean)
// @group data
// @description
// Returns whether the entity type is a hostile monster.
// -->
tagProcessor.registerTag(ElementTag.class, "is_monster", (attribute, object) -> {
return new ElementTag(object.isMonsterType());
});
// <--[tag]
// @attribute <EntityTag.is_mob>
// @returns ElementTag(Boolean)
// @group data
// @description
// Returns whether the entity type is a mob (Not a player or NPC).
// -->
tagProcessor.registerTag(ElementTag.class, "is_mob", (attribute, object) -> {
return new ElementTag(object.isMobType());
});
// <--[tag]
// @attribute <EntityTag.is_npc>
// @returns ElementTag(Boolean)
// @group data
// @description
// Returns whether the entity is a Citizens NPC.
// -->
registerSpawnedOnlyTag(ElementTag.class, "is_npc", (attribute, object) -> {
return new ElementTag(object.isCitizensNPC());
});
// <--[tag]
// @attribute <EntityTag.is_player>
// @returns ElementTag(Boolean)
// @group data
// @description
// Returns whether the entity is a player.
// Works with offline players.
// -->
tagProcessor.registerTag(ElementTag.class, "is_player", (attribute, object) -> {
return new ElementTag(object.isPlayer());
});
// <--[tag]
// @attribute <EntityTag.is_projectile>
// @returns ElementTag(Boolean)
// @group data
// @description
// Returns whether the entity type is a projectile.
// -->
tagProcessor.registerTag(ElementTag.class, "is_projectile", (attribute, object) -> {
if (object.getBukkitEntity() == null && object.entity_type != null) {
return new ElementTag(Projectile.class.isAssignableFrom(object.entity_type.getBukkitEntityType().getEntityClass()));
}
return new ElementTag(object.isProjectile());
});
// ///////////////////
// PROPERTY ATTRIBUTES
// ///////////////
// <--[tag]
// @attribute <EntityTag.tameable>
// @returns ElementTag(Boolean)
// @group properties
// @description
// Returns whether the entity is tameable.
// If this returns true, it will enable access to:
// <@link mechanism EntityTag.tame>, <@link mechanism EntityTag.owner>,
// <@link tag EntityTag.is_tamed>, and <@link tag EntityTag.owner>
// -->
registerSpawnedOnlyTag(ElementTag.class, "tameable", (attribute, object) -> {
return new ElementTag(EntityTame.describes(object));
}, "is_tameable");
// <--[tag]
// @attribute <EntityTag.ageable>
// @returns ElementTag(Boolean)
// @group properties
// @description
// Returns whether the entity is ageable.
// If this returns true, it will enable access to:
// <@link mechanism EntityTag.age>, <@link mechanism EntityTag.age_lock>,
// <@link tag EntityTag.is_baby>, <@link tag EntityTag.age>,
// and <@link tag EntityTag.is_age_locked>
// -->
registerSpawnedOnlyTag(ElementTag.class, "ageable", (attribute, object) -> {
return new ElementTag(EntityAge.describes(object));
}, "is_ageable");
// <--[tag]
// @attribute <EntityTag.colorable>
// @returns ElementTag(Boolean)
// @group properties
// @description
// Returns whether the entity can be colored.
// If this returns true, it will enable access to:
// <@link mechanism EntityTag.color> and <@link tag EntityTag.color>
// -->
registerSpawnedOnlyTag(ElementTag.class, "colorable", (attribute, object) -> {
return new ElementTag(EntityColor.describes(object));
}, "is_colorable");
// <--[tag]
// @attribute <EntityTag.experience>
// @returns ElementTag(Number)
// @mechanism EntityTag.experience
// @group properties
// @description
// Returns the experience value of this experience orb entity.
// -->
registerSpawnedOnlyTag(ElementTag.class, "experience", (attribute, object) -> {
if (!(object.getBukkitEntity() instanceof ExperienceOrb)) {
return null;
}
return new ElementTag(((ExperienceOrb) object.getBukkitEntity()).getExperience());
});
// <--[tag]
// @attribute <EntityTag.fuse_ticks>
// @returns ElementTag(Number)
// @mechanism EntityTag.fuse_ticks
// @group properties
// @description
// Returns the number of ticks until the explosion of the primed TNT.
// -->
registerSpawnedOnlyTag(ElementTag.class, "fuse_ticks", (attribute, object) -> {
if (!(object.getBukkitEntity() instanceof TNTPrimed)) {
return null;
}
return new ElementTag(((TNTPrimed) object.getBukkitEntity()).getFuseTicks());
});
// <--[tag]
// @attribute <EntityTag.dragon_phase>
// @returns ElementTag
// @mechanism EntityTag.dragon_phase
// @group properties
// @description
// Returns the phase an EnderDragon is currently in.
// Valid phases: <@link url https://hub.spigotmc.org/javadocs/spigot/org/bukkit/entity/EnderDragon.Phase.html>
// -->
registerSpawnedOnlyTag(ElementTag.class, "dragon_phase", (attribute, object) -> {
if (!(object.getBukkitEntity() instanceof EnderDragon)) {
return null;
}
return new ElementTag(((EnderDragon) object.getLivingEntity()).getPhase().name());
});
// <--[tag]
// @attribute <EntityTag.weapon_damage[(<entity>)]>
// @returns ElementTag(Number)
// @group properties
// @description
// Returns the amount of damage the entity will do based on its held item.
// Optionally, specify a target entity to test how much damage will be done to that specific target
// (modified based on enchantments and that entity's armor/status/etc).
// Note that the result will not always be completely exact, as it doesn't take into account some specific factors
// (eg sweeping vs single-hit, etc).
// -->
registerSpawnedOnlyTag(ElementTag.class, "weapon_damage", (attribute, object) -> {
Entity target = null;
if (attribute.hasParam()) {
target = attribute.paramAsType(EntityTag.class).getBukkitEntity();
}
return new ElementTag(NMSHandler.getEntityHelper().getDamageTo(object.getLivingEntity(), target));
});
// <--[tag]
// @attribute <EntityTag.skin_layers>
// @returns ListTag
// @mechanism EntityTag.skin_layers
// @description
// Returns the skin layers currently visible on a player-type entity.
// Output is a list of values from the set of:
// CAPE, HAT, JACKET, LEFT_PANTS, LEFT_SLEEVE, RIGHT_PANTS, or RIGHT_SLEEVE.
// -->
registerSpawnedOnlyTag(ListTag.class, "skin_layers", (attribute, object) -> {
byte flags = NMSHandler.getPlayerHelper().getSkinLayers((Player) object.getBukkitEntity());
ListTag result = new ListTag();
for (PlayerHelper.SkinLayer layer : PlayerHelper.SkinLayer.values()) {
if ((flags & layer.flag) != 0) {
result.add(layer.name());
}
}
return result;
});
// <--[tag]
// @attribute <EntityTag.is_disguised[(<player>)]>
// @returns ElementTag(Boolean)
// @group properties
// @description
// Returns whether the entity is currently disguised, either globally (if no context input given), or to the specified player.
// Relates to <@link command disguise>.
// -->
registerSpawnedOnlyTag(ElementTag.class, "is_disguised", (attribute, object) -> {
HashMap<UUID, DisguiseCommand.TrackedDisguise> map = DisguiseCommand.disguises.get(object.getUUID());
if (map == null) {
return new ElementTag(false);
}
if (attribute.hasParam()) {
PlayerTag player = attribute.paramAsType(PlayerTag.class);
if (player == null) {
attribute.echoError("Invalid player for is_disguised tag.");
return null;
}
return new ElementTag(map.containsKey(player.getUUID()) || map.containsKey(null));
} else {
return new ElementTag(map.containsKey(null));
}
});
// <--[tag]
// @attribute <EntityTag.disguised_type[(<player>)]>
// @returns EntityTag
// @group properties
// @description
// Returns the entity type the entity is disguised as, either globally (if no context input given), or to the specified player.
// Relates to <@link command disguise>.
// -->
registerSpawnedOnlyTag(EntityTag.class, "disguised_type", (attribute, object) -> {
HashMap<UUID, DisguiseCommand.TrackedDisguise> map = DisguiseCommand.disguises.get(object.getUUID());
if (map == null) {
return null;
}
DisguiseCommand.TrackedDisguise disguise;
if (attribute.hasParam()) {
PlayerTag player = attribute.paramAsType(PlayerTag.class);
if (player == null) {
attribute.echoError("Invalid player for is_disguised tag.");
return null;
}
disguise = map.get(player.getUUID());
if (disguise == null) {
disguise = map.get(null);
}
} else {
disguise = map.get(null);
}
if (disguise == null) {
return null;
}
return disguise.as.duplicate();
});
// <--[tag]
// @attribute <EntityTag.disguise_to_others[(<player>)]>
// @returns EntityTag
// @group properties
// @description
// Returns the fake entity used to disguise the entity in other's views, either globally (if no context input given), or to the specified player.
// Relates to <@link command disguise>.
// -->
registerSpawnedOnlyTag(EntityTag.class, "disguise_to_others", (attribute, object) -> {
HashMap<UUID, DisguiseCommand.TrackedDisguise> map = DisguiseCommand.disguises.get(object.getUUID());
if (map == null) {
return null;
}
DisguiseCommand.TrackedDisguise disguise;
if (attribute.hasParam()) {
PlayerTag player = attribute.paramAsType(PlayerTag.class);
if (player == null) {
attribute.echoError("Invalid player for is_disguised tag.");
return null;
}
disguise = map.get(player.getUUID());
if (disguise == null) {
disguise = map.get(null);
}
} else {
disguise = map.get(null);
}
if (disguise == null) {
return null;
}
if (disguise.toOthers == null) {
return null;
}
return disguise.toOthers.entity;
});
// <--[tag]
// @attribute <EntityTag.describe>
// @returns EntityTag
// @group properties
// @description
// Returns the entity's full description, including all properties.
// -->
tagProcessor.registerTag(EntityTag.class, "describe", (attribute, object) -> {
return object.describe(attribute.context);
});
// <--[tag]
// @attribute <EntityTag.advanced_matches[<matcher>]>
// @returns ElementTag(Boolean)
// @group element checking
// @description
// Returns whether the entity matches some matcher text, using the system behind <@link language Advanced Script Event Matching>.
// -->
tagProcessor.registerTag(ElementTag.class, "advanced_matches", (attribute, object) -> {
if (!attribute.hasParam()) {
return null;
}
return new ElementTag(BukkitScriptEvent.tryEntity(object, attribute.getParam()));
});
// <--[tag]
// @attribute <EntityTag.has_equipped[<item-matcher>]>
// @returns ElementTag(Boolean)
// @group element checking
// @description
// Returns whether the entity has any armor equipment item that matches the given item matcher, using the system behind <@link language Advanced Script Event Matching>.
// For example, has_equipped[diamond_*] will return true if the entity is wearing at least one piece of diamond armor.
// -->
registerSpawnedOnlyTag(ElementTag.class, "has_equipped", (attribute, object) -> {
if (!attribute.hasParam()) {
return null;
}
if (!object.isLivingEntity()) {
return null;
}
String matcher = attribute.getParam();
for (ItemStack item : object.getLivingEntity().getEquipment().getArmorContents()) {
if (BukkitScriptEvent.tryItem(new ItemTag(item), matcher)) {
return new ElementTag(true);
}
}
return new ElementTag(false);
});
// <--[tag]
// @attribute <EntityTag.loot_table_id>
// @returns ElementTag
// @description
// Returns an element indicating the minecraft key for the loot-table for the entity (if any).
// -->
registerSpawnedOnlyTag(ElementTag.class, "loot_table_id", (attribute, object) -> {
if (object.getBukkitEntity() instanceof Lootable) {
LootTable table = ((Lootable) object.getBukkitEntity()).getLootTable();
if (table != null) {
return new ElementTag(table.getKey().toString());
}
}
return null;
});
// <--[tag]
// @attribute <EntityTag.fish_hook_state>
// @returns ElementTag
// @description
// Returns the current state of the fish hook, as any of: UNHOOKED, HOOKED_ENTITY, BOBBING (unhooked means the fishing hook is in the air or on ground).
// -->
registerSpawnedOnlyTag(ElementTag.class, "fish_hook_state", (attribute, object) -> {
if (!(object.getBukkitEntity() instanceof FishHook)) {
attribute.echoError("EntityTag.fish_hook_state is only valid for fish hooks.");
return null;
}
return new ElementTag(((FishHook) object.getBukkitEntity()).getState().name());
});
// <--[tag]
// @attribute <EntityTag.fish_hook_lure_time>
// @returns DurationTag
// @mechanism EntityTag.fish_hook_lure_time
// @description
// Returns the remaining time before this fish hook will lure a fish.
// -->
registerSpawnedOnlyTag(DurationTag.class, "fish_hook_lure_time", (attribute, object) -> {
if (!(object.getBukkitEntity() instanceof FishHook)) {
attribute.echoError("EntityTag.fish_hook_lure_time is only valid for fish hooks.");
return null;
}
return new DurationTag((long) NMSHandler.getFishingHelper().getLureTime((FishHook) object.getBukkitEntity()));
});
// <--[tag]
// @attribute <EntityTag.fish_hook_min_lure_time>
// @returns DurationTag
// @mechanism EntityTag.fish_hook_min_lure_time
// @description
// Returns the minimum possible time before this fish hook can lure a fish.
// -->
registerSpawnedOnlyTag(DurationTag.class, "fish_hook_min_lure_time", (attribute, object) -> {
if (!(object.getBukkitEntity() instanceof FishHook)) {
attribute.echoError("EntityTag.fish_hook_min_lure_time is only valid for fish hooks.");
return null;
}
return new DurationTag((long) ((FishHook) object.getBukkitEntity()).getMinWaitTime());
});
// <--[tag]
// @attribute <EntityTag.fish_hook_max_lure_time>
// @returns DurationTag
// @mechanism EntityTag.fish_hook_max_lure_time
// @description
// Returns the maximum possible time before this fish hook will lure a fish.
// -->
registerSpawnedOnlyTag(DurationTag.class, "fish_hook_max_lure_time", (attribute, object) -> {
if (!(object.getBukkitEntity() instanceof FishHook)) {
attribute.echoError("EntityTag.fish_hook_max_lure_time is only valid for fish hooks.");
return null;
}
return new DurationTag((long) ((FishHook) object.getBukkitEntity()).getMaxWaitTime());
});
// <--[tag]
// @attribute <EntityTag.fish_hook_hooked_entity>
// @returns EntityTag
// @mechanism EntityTag.fish_hook_hooked_entity
// @description
// Returns the entity this fish hook is attached to.
// -->
registerSpawnedOnlyTag(EntityTag.class, "fish_hook_hooked_entity", (attribute, object) -> {
if (!(object.getBukkitEntity() instanceof FishHook)) {
attribute.echoError("EntityTag.fish_hook_hooked_entity is only valid for fish hooks.");
return null;
}
Entity entity = ((FishHook) object.getBukkitEntity()).getHookedEntity();
return entity != null ? new EntityTag(entity) : null;
});
// <--[tag]
// @attribute <EntityTag.fish_hook_apply_lure>
// @returns ElementTag(Boolean)
// @mechanism EntityTag.fish_hook_apply_lure
// @description
// Returns whether this fish hook should respect the lure enchantment.
// Every level of lure enchantment reduces lure time by 5 seconds.
// -->
registerSpawnedOnlyTag(ElementTag.class, "fish_hook_apply_lure", (attribute, object) -> {
if (!(object.getBukkitEntity() instanceof FishHook)) {
attribute.echoError("EntityTag.fish_hook_apply_lure is only valid for fish hooks.");
return null;
}
return new ElementTag(((FishHook) object.getBukkitEntity()).getApplyLure());
});
// <--[tag]
// @attribute <EntityTag.fish_hook_in_open_water>
// @returns ElementTag(Boolean)
// @description
// Returns whether this fish hook is in open water. Fish hooks in open water can catch treasure.
// See <@link url https://minecraft.fandom.com/wiki/Fishing> for more info.
// -->
registerSpawnedOnlyTag(ElementTag.class, "fish_hook_in_open_water", (attribute, object) -> {
if (!(object.getBukkitEntity() instanceof FishHook)) {
attribute.echoError("EntityTag.fish_hook_in_open_water is only valid for fish hooks.");
return null;
}
return new ElementTag(((FishHook) object.getBukkitEntity()).isInOpenWater());
});
// <--[tag]
// @attribute <EntityTag.attached_entities[(<player>)]>
// @returns ListTag(EntityTag)
// @description
// Returns the entities attached to this entity by <@link command attach>.
// Optionally, specify a player. If specified, will return entities attached visible to that player. If not specified, returns entities globally attached.
// -->
registerSpawnedOnlyTag(ListTag.class, "attached_entities", (attribute, object) -> {
PlayerTag player = attribute.hasParam() ? attribute.paramAsType(PlayerTag.class) : null;
EntityAttachmentHelper.EntityAttachedToMap data = EntityAttachmentHelper.toEntityToData.get(object.getUUID());
ListTag result = new ListTag();
if (data == null) {
return result;
}
for (EntityAttachmentHelper.PlayerAttachMap map : data.attachedToMap.values()) {
if (player == null || map.getAttachment(player.getUUID()) != null) {
result.addObject(map.attached);
}
}
return result;
});
// <--[tag]
// @attribute <EntityTag.attached_to[(<player>)]>
// @returns EntityTag
// @description
// Returns the entity that this entity was attached to by <@link command attach>.
// Optionally, specify a player. If specified, will return entity attachment visible to that player. If not specified, returns any entity global attachment.
// -->
registerSpawnedOnlyTag(EntityTag.class, "attached_to", (attribute, object) -> {
PlayerTag player = attribute.hasParam() ? attribute.paramAsType(PlayerTag.class) : null;
EntityAttachmentHelper.PlayerAttachMap data = EntityAttachmentHelper.attachedEntityToData.get(object.getUUID());
if (data == null) {
return null;
}
EntityAttachmentHelper.AttachmentData attached = data.getAttachment(player == null ? null : player.getUUID());
if (attached == null) {
return null;
}
return attached.to;
});
// <--[tag]
// @attribute <EntityTag.attached_offset[(<player>)]>
// @returns LocationTag
// @description
// Returns the offset of an attachment for this entity to another that was attached by <@link command attach>.
// Optionally, specify a player. If specified, will return entity attachment visible to that player. If not specified, returns any entity global attachment.
// -->
registerSpawnedOnlyTag(LocationTag.class, "attached_offset", (attribute, object) -> {
PlayerTag player = attribute.hasParam() ? attribute.paramAsType(PlayerTag.class) : null;
EntityAttachmentHelper.PlayerAttachMap data = EntityAttachmentHelper.attachedEntityToData.get(object.getUUID());
if (data == null) {
return null;
}
EntityAttachmentHelper.AttachmentData attached = data.getAttachment(player == null ? null : player.getUUID());
if (attached == null) {
return null;
}
return attached.positionalOffset == null ? null : new LocationTag(attached.positionalOffset);
});
// <--[tag]
// @attribute <EntityTag.attack_cooldown_duration>
// @returns DurationTag
// @mechanism EntityTag.attack_cooldown
// @description
// Returns the amount of time that passed since the start of the attack cooldown.
// -->
registerSpawnedOnlyTag(DurationTag.class, "attack_cooldown_duration", (attribute, object) -> {
if (!(object.getBukkitEntity() instanceof Player)) {
attribute.echoError("Only player-type entities can have attack_cooldowns!");
return null;
}
return new DurationTag((long) NMSHandler.getPlayerHelper().ticksPassedDuringCooldown((Player) object.getLivingEntity()));
});
// <--[tag]
// @attribute <EntityTag.attack_cooldown_max_duration>
// @returns DurationTag
// @mechanism EntityTag.attack_cooldown
// @description
// Returns the maximum amount of time that can pass before the player's main hand has returned
// to its original place after the cooldown has ended.
// NOTE: This is slightly inaccurate and may not necessarily match with the actual attack
// cooldown progress.
// -->
registerSpawnedOnlyTag(DurationTag.class, "attack_cooldown_max_duration", (attribute, object) -> {
if (!(object.getBukkitEntity() instanceof Player)) {
attribute.echoError("Only player-type entities can have attack_cooldowns!");
return null;
}
return new DurationTag((long) NMSHandler.getPlayerHelper().getMaxAttackCooldownTicks((Player) object.getLivingEntity()));
});
// <--[tag]
// @attribute <EntityTag.attack_cooldown_percent>
// @returns ElementTag(Decimal)
// @mechanism EntityTag.attack_cooldown_percent
// @description
// Returns the progress of the attack cooldown. 0 means that the attack cooldown has just
// started, while 100 means that the attack cooldown has finished.
// NOTE: This may not match exactly with the clientside attack cooldown indicator.
// -->
registerSpawnedOnlyTag(ElementTag.class, "attack_cooldown_percent", (attribute, object) -> {
if (!(object.getBukkitEntity() instanceof Player)) {
attribute.echoError("Only player-type entities can have attack_cooldowns!");
return null;
}
return new ElementTag(NMSHandler.getPlayerHelper().getAttackCooldownPercent((Player) object.getLivingEntity()) * 100);
});
// <--[tag]
// @attribute <EntityTag.is_hand_raised>
// @returns ElementTag(Boolean)
// @mechanism EntityTag.attack_cooldown_percent
// @description
// Returns whether the player's hand is currently raised. Valid for players and player-type NPCs.
// A player's hand is raised when they are blocking with a shield, aiming a crossbow, looking through a spyglass, etc.
// -->
registerSpawnedOnlyTag(ElementTag.class, "is_hand_raised", (attribute, object) -> {
if (!(object.getBukkitEntity() instanceof HumanEntity)) {
attribute.echoError("Only player-type entities can have is_hand_raised!");
return null;
}
return new ElementTag(((HumanEntity) object.getLivingEntity()).isHandRaised());
});
}
Aggregations