Consistently format heads, add hover display
This commit is contained in:
1 parent
2008150b11
commit
1ca9aaed36
15 files changed
+507
-350
No files matched your search
@@ -19,11 +19,14 @@ import com.tcoded.playerbountiesplus.hook.currency.DiamondBankOGHook;
|
||||
import com.tcoded.playerbountiesplus.hook.logging.CoreProtectHook;
|
||||
import com.tcoded.playerbountiesplus.hook.currency.EconomyHook;
|
||||
import com.tcoded.playerbountiesplus.hook.team.TeamHook;
|
||||
import com.tcoded.playerbountiesplus.listener.BountyHeadLabelListener;
|
||||
import com.tcoded.playerbountiesplus.listener.BountyHeadListener;
|
||||
import com.tcoded.playerbountiesplus.listener.BountyIncreasePromptListener;
|
||||
import com.tcoded.playerbountiesplus.listener.DeathListener;
|
||||
import com.tcoded.playerbountiesplus.listener.GuiProtectionListener;
|
||||
import com.tcoded.playerbountiesplus.manager.BountyDataManager;
|
||||
import com.tcoded.playerbountiesplus.util.BountyHeadFormatter;
|
||||
import com.tcoded.playerbountiesplus.util.BountyHeadMetadata;
|
||||
import com.tcoded.playerbountiesplus.util.LangUtil;
|
||||
|
||||
import net.luckperms.api.LuckPerms;
|
||||
@@ -49,6 +52,8 @@ public final class PlayerBountiesOG extends JavaPlugin {
|
||||
|
||||
// Utilities.
|
||||
private LangUtil langUtil;
|
||||
private BountyHeadFormatter bountyHeadFormatter;
|
||||
private BountyHeadMetadata bountyHeadMetadata;
|
||||
|
||||
// Managers.
|
||||
private BountyDataManager bountyDataManager;
|
||||
@@ -67,6 +72,7 @@ public final class PlayerBountiesOG extends JavaPlugin {
|
||||
private CoreProtectHook coreProtectHook;
|
||||
|
||||
private BountyIncreasePromptListener bountyIncreasePromptListener;
|
||||
private BountyHeadLabelListener bountyHeadLabelListener;
|
||||
|
||||
public PlayerBountiesOG() {
|
||||
|
||||
@@ -121,6 +127,8 @@ public final class PlayerBountiesOG extends JavaPlugin {
|
||||
|
||||
// Utils.
|
||||
this.reloadLang();
|
||||
this.bountyHeadFormatter = new BountyHeadFormatter(this.diamondBankAPI, this.luckPerms);
|
||||
this.bountyHeadMetadata = new BountyHeadMetadata(this);
|
||||
|
||||
// Managers.
|
||||
this.bountyDataManager = new BountyDataManager(this);
|
||||
@@ -158,12 +166,12 @@ public final class PlayerBountiesOG extends JavaPlugin {
|
||||
}
|
||||
|
||||
// Listeners.
|
||||
this.getServer().getPluginManager().registerEvents(new DeathListener(this, this.diamondBankAPI, this.luckPerms),
|
||||
this);
|
||||
this.getServer().getPluginManager().registerEvents(new DeathListener(this), this);
|
||||
this.bountyIncreasePromptListener = new BountyIncreasePromptListener(this);
|
||||
|
||||
this.getServer().getPluginManager().registerEvents(
|
||||
new BountyHeadListener(this, this.diamondBankAPI, this.luckPerms, this.coreProtectHook), this);
|
||||
this.getServer().getPluginManager().registerEvents(new BountyHeadListener(this), this);
|
||||
this.bountyHeadLabelListener = new BountyHeadLabelListener(this);
|
||||
this.getServer().getPluginManager().registerEvents(this.bountyHeadLabelListener, this);
|
||||
this.getServer().getPluginManager().registerEvents(this.bountyIncreasePromptListener, this);
|
||||
this.getServer().getPluginManager().registerEvents(new GuiProtectionListener(this), this);
|
||||
|
||||
@@ -188,6 +196,12 @@ public final class PlayerBountiesOG extends JavaPlugin {
|
||||
@Override
|
||||
public void onDisable() {
|
||||
|
||||
if (this.bountyHeadLabelListener != null) {
|
||||
|
||||
this.bountyHeadLabelListener.shutdown();
|
||||
|
||||
}
|
||||
|
||||
HandlerList.unregisterAll(this);
|
||||
|
||||
UtilitiesOG.logToConsole(getPrefix(), "PlayerBounties-OG has been shut down successfully!");
|
||||
@@ -236,6 +250,18 @@ public final class PlayerBountiesOG extends JavaPlugin {
|
||||
|
||||
}
|
||||
|
||||
public BountyHeadFormatter getBountyHeadFormatter() {
|
||||
|
||||
return this.bountyHeadFormatter;
|
||||
|
||||
}
|
||||
|
||||
public BountyHeadMetadata getBountyHeadMetadata() {
|
||||
|
||||
return this.bountyHeadMetadata;
|
||||
|
||||
}
|
||||
|
||||
public BountyIncreasePromptListener getBountyIncreasePromptListener() {
|
||||
|
||||
return this.bountyIncreasePromptListener;
|
||||
|
||||
@@ -75,14 +75,15 @@ public class BountyAddCmd {
|
||||
}
|
||||
|
||||
final OfflinePlayer target = Bukkit.getOfflinePlayer(targetNameArg);
|
||||
if (target.getUniqueId() == null) {
|
||||
if (target.getUniqueId() != null) {
|
||||
|
||||
UtilitiesOG.trueogMessage(player, plugin.getLang().getColored("command.bounty.add.player-not-found"));
|
||||
return true;
|
||||
return addBounty(plugin, player, target.getUniqueId(), target.getName(), amount, true);
|
||||
|
||||
}
|
||||
|
||||
return addBounty(plugin, player, target.getUniqueId(), target.getName(), amount, true);
|
||||
UtilitiesOG.trueogMessage(player, plugin.getLang().getColored("command.bounty.add.player-not-found"));
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
@@ -247,13 +248,7 @@ public class BountyAddCmd {
|
||||
final RegisteredServiceProvider<LuckPerms> provider = plugin.getServer().getServicesManager()
|
||||
.getRegistration(LuckPerms.class);
|
||||
|
||||
if (provider == null) {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
return provider.getProvider();
|
||||
return provider == null ? null : provider.getProvider();
|
||||
|
||||
}
|
||||
|
||||
@@ -312,13 +307,7 @@ public class BountyAddCmd {
|
||||
final String cleaned = StringUtils.trimToEmpty(formatted).replaceAll("(?i)(?:\\s*(?:<reset>|[&§]r))+$", "")
|
||||
.replaceAll("\\s*>$", "");
|
||||
|
||||
if (cleaned.isBlank()) {
|
||||
|
||||
return fallbackName;
|
||||
|
||||
}
|
||||
|
||||
return cleaned;
|
||||
return cleaned.isBlank() ? fallbackName : cleaned;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -297,13 +297,7 @@ public class BountySetCmd {
|
||||
final RegisteredServiceProvider<LuckPerms> provider = plugin.getServer().getServicesManager()
|
||||
.getRegistration(LuckPerms.class);
|
||||
|
||||
if (provider == null) {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
return provider.getProvider();
|
||||
return provider == null ? null : provider.getProvider();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.tcoded.playerbountiesplus.command.bounty;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
@@ -15,10 +14,8 @@ import org.bukkit.entity.Player;
|
||||
|
||||
import com.tcoded.playerbountiesplus.PlayerBountiesOG;
|
||||
import com.tcoded.playerbountiesplus.gui.MainBountyGui;
|
||||
import com.tcoded.playerbountiesplus.util.BountyHeadFormatter;
|
||||
|
||||
import net.luckperms.api.LuckPerms;
|
||||
import net.luckperms.api.cacheddata.CachedMetaData;
|
||||
import net.luckperms.api.model.user.User;
|
||||
import net.trueog.diamondbankog.api.DiamondBankAPIJava;
|
||||
import net.trueog.utilitiesog.UtilitiesOG;
|
||||
|
||||
@@ -45,6 +42,8 @@ public class BountyTopCmd {
|
||||
|
||||
private static List<MainBountyGui.BountyGuiEntry> buildGuiEntries(PlayerBountiesOG plugin) {
|
||||
|
||||
final BountyHeadFormatter formatter = plugin.getBountyHeadFormatter();
|
||||
|
||||
final Set<Map.Entry<UUID, Double>> bountiesSet = plugin.getBountyDataManager().getBounties().entrySet();
|
||||
final List<Map.Entry<UUID, Double>> bounties = new ArrayList<>(bountiesSet);
|
||||
|
||||
@@ -68,7 +67,7 @@ public class BountyTopCmd {
|
||||
|
||||
}
|
||||
|
||||
final String displayName = resolveLuckPermsDisplayName(plugin.getLuckPerms(), entry.getKey(), targetName);
|
||||
final String displayName = formatter.resolvePlayerDisplay(entry.getKey(), targetName);
|
||||
|
||||
entries.add(new MainBountyGui.BountyGuiEntry(entry.getKey(), targetName, displayName, entry.getValue()));
|
||||
|
||||
@@ -78,84 +77,12 @@ public class BountyTopCmd {
|
||||
|
||||
}
|
||||
|
||||
private static String resolveLuckPermsDisplayName(LuckPerms luckPerms, UUID playerId, String playerName) {
|
||||
|
||||
final String safeName = StringUtils.defaultIfBlank(playerName, "Unknown Player");
|
||||
if (luckPerms == null) {
|
||||
|
||||
return "&f" + safeName;
|
||||
|
||||
}
|
||||
|
||||
final User user = luckPerms.getUserManager().getUser(playerId);
|
||||
if (user == null) {
|
||||
|
||||
return "&f" + safeName;
|
||||
|
||||
}
|
||||
|
||||
final CachedMetaData meta = user.getCachedData().getMetaData();
|
||||
final String prefix = StringUtils.trim(StringUtils.defaultString(meta.getPrefix()).replace('§', '&'));
|
||||
final String suffix = StringUtils.trim(StringUtils.defaultString(meta.getSuffix()).replace('§', '&'));
|
||||
final boolean metaContainsName = containsVisibleName(prefix, safeName) || containsVisibleName(suffix, safeName);
|
||||
|
||||
final StringBuilder out = new StringBuilder();
|
||||
if (!prefix.isBlank()) {
|
||||
|
||||
out.append(prefix).append(' ');
|
||||
|
||||
}
|
||||
|
||||
if (!metaContainsName) {
|
||||
|
||||
out.append(safeName);
|
||||
|
||||
}
|
||||
|
||||
if (!suffix.isBlank()) {
|
||||
|
||||
out.append(' ').append(suffix);
|
||||
|
||||
}
|
||||
|
||||
return sanitizeDisplay(out.toString(), safeName);
|
||||
|
||||
}
|
||||
|
||||
private static String sanitizeDisplay(String formatted, String fallbackName) {
|
||||
|
||||
final String cleaned = StringUtils.trimToEmpty(formatted).replaceAll("(?i)(?:\\s*(?:<reset>|[&§]r))+$", "")
|
||||
.replaceAll("\\s*>$", "");
|
||||
|
||||
if (cleaned.isBlank()) {
|
||||
|
||||
return fallbackName;
|
||||
|
||||
}
|
||||
|
||||
return cleaned;
|
||||
|
||||
}
|
||||
|
||||
private static boolean containsVisibleName(String text, String playerName) {
|
||||
|
||||
if (text == null || playerName == null || playerName.isBlank()) {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
final String normalizedText = StringUtils.lowerCase(UtilitiesOG.stripFormatting(text), Locale.ROOT);
|
||||
final String normalizedName = StringUtils.lowerCase(playerName, Locale.ROOT);
|
||||
|
||||
return StringUtils.contains(normalizedText, normalizedName);
|
||||
|
||||
}
|
||||
|
||||
private static void sendTextTopList(PlayerBountiesOG plugin, DiamondBankAPIJava diamondBankAPI,
|
||||
CommandSender sender)
|
||||
{
|
||||
|
||||
final BountyHeadFormatter formatter = plugin.getBountyHeadFormatter();
|
||||
|
||||
final Set<Map.Entry<UUID, Double>> bountiesSet = plugin.getBountyDataManager().getBounties().entrySet();
|
||||
final List<Map.Entry<UUID, Double>> bounties = new ArrayList<>(bountiesSet);
|
||||
|
||||
@@ -184,8 +111,7 @@ public class BountyTopCmd {
|
||||
.shardsToDiamonds(diamondBankAPI.diamondsToShards(entry.getValue()));
|
||||
|
||||
strb.append("&7 - ");
|
||||
final String displayName = resolveLuckPermsDisplayName(plugin.getLuckPerms(), entry.getKey(),
|
||||
targetName);
|
||||
final String displayName = formatter.resolvePlayerDisplay(entry.getKey(), targetName);
|
||||
|
||||
strb.append(displayName);
|
||||
strb.append(": &b");
|
||||
|
||||
@@ -390,13 +390,7 @@ public class MainBountyGui extends GUIBase {
|
||||
|
||||
private String safeName(String name) {
|
||||
|
||||
if (name == null || name.isBlank()) {
|
||||
|
||||
return "Unknown Player";
|
||||
|
||||
}
|
||||
|
||||
return name;
|
||||
return name == null || name.isBlank() ? "Unknown Player" : name;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -113,4 +113,4 @@ public class CoreProtectHook {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -30,13 +30,8 @@ public abstract class AbstractTeamHook implements TeamHook {
|
||||
public String getAuthor() {
|
||||
|
||||
final List<String> authors = this.teamPlugin.getPluginMeta().getAuthors();
|
||||
if (authors.isEmpty()) {
|
||||
|
||||
return "N/A";
|
||||
|
||||
}
|
||||
|
||||
return authors.get(0);
|
||||
return authors.isEmpty() ? "N/A" : authors.get(0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -35,13 +35,7 @@ public class SimpleClansHook extends AbstractTeamHook {
|
||||
|
||||
}
|
||||
|
||||
if (clan2 == null) {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
return clan1 == clan2;
|
||||
return clan2 == null ? false : clan1 == clan2;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
package com.tcoded.playerbountiesplus.listener;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.bukkit.FluidCollisionMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.Skull;
|
||||
import org.bukkit.entity.ArmorStand;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
import org.bukkit.util.RayTraceResult;
|
||||
|
||||
import com.tcoded.playerbountiesplus.PlayerBountiesOG;
|
||||
import com.tcoded.playerbountiesplus.util.BountyHeadData;
|
||||
|
||||
public final class BountyHeadLabelListener implements Listener {
|
||||
|
||||
private static final long UPDATE_PERIOD_TICKS = 2L;
|
||||
|
||||
private final PlayerBountiesOG plugin;
|
||||
private final Map<HeadLabelKey, ArmorStand> activeLabels = new HashMap<>();
|
||||
private final BukkitTask tickTask;
|
||||
|
||||
public BountyHeadLabelListener(PlayerBountiesOG plugin) {
|
||||
|
||||
this.plugin = plugin;
|
||||
this.tickTask = plugin.getServer().getScheduler().runTaskTimer(plugin, this::tick, UPDATE_PERIOD_TICKS,
|
||||
UPDATE_PERIOD_TICKS);
|
||||
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
|
||||
if (tickTask != null) {
|
||||
|
||||
tickTask.cancel();
|
||||
|
||||
}
|
||||
|
||||
clearLabels();
|
||||
|
||||
}
|
||||
|
||||
private void tick() {
|
||||
|
||||
if (!isHoverModeEnabled()) {
|
||||
|
||||
clearLabels();
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
final Set<HeadLabelKey> visibleTargets = new HashSet<>();
|
||||
for (Player player : plugin.getServer().getOnlinePlayers()) {
|
||||
|
||||
final HeadTarget target = findTargetedHead(player);
|
||||
if (target == null) {
|
||||
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
visibleTargets.add(target.key());
|
||||
upsertLabel(target);
|
||||
|
||||
}
|
||||
|
||||
final Set<HeadLabelKey> staleLabels = new HashSet<>(activeLabels.keySet());
|
||||
staleLabels.removeAll(visibleTargets);
|
||||
staleLabels.forEach(this::removeLabel);
|
||||
|
||||
}
|
||||
|
||||
private HeadTarget findTargetedHead(Player player) {
|
||||
|
||||
final double maxRange = Math.max(1D, plugin.getConfig().getDouble("bounty-head-label-range", 8D));
|
||||
final RayTraceResult rayTrace = player.getWorld().rayTraceBlocks(player.getEyeLocation(),
|
||||
player.getEyeLocation().getDirection(), maxRange, FluidCollisionMode.NEVER, true);
|
||||
if (rayTrace == null) {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
final Block hitBlock = rayTrace.getHitBlock();
|
||||
if (hitBlock == null || !isHeadMaterial(hitBlock.getType())) {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
final BlockState state = hitBlock.getState();
|
||||
if (!(state instanceof Skull skull)) {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
final BountyHeadData headData = plugin.getBountyHeadMetadata().read(skull.getPersistentDataContainer());
|
||||
if (headData == null) {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
return new HeadTarget(HeadLabelKey.fromBlock(hitBlock), hitBlock.getLocation(), headData);
|
||||
|
||||
}
|
||||
|
||||
private void upsertLabel(HeadTarget target) {
|
||||
|
||||
final ArmorStand existing = activeLabels.get(target.key());
|
||||
if (existing != null && existing.isValid()) {
|
||||
|
||||
existing.customName(plugin.getBountyHeadFormatter().buildHoverLabel(target.data()));
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
final Location labelLocation = target.location().add(0.5D, 0.85D, 0.5D);
|
||||
final ArmorStand label = target.location().getWorld().spawn(labelLocation, ArmorStand.class, stand -> {
|
||||
|
||||
stand.setInvisible(true);
|
||||
stand.setGravity(false);
|
||||
stand.setMarker(true);
|
||||
stand.setSmall(true);
|
||||
stand.setInvulnerable(true);
|
||||
stand.setSilent(true);
|
||||
stand.setPersistent(false);
|
||||
stand.setBasePlate(false);
|
||||
stand.setArms(false);
|
||||
stand.customName(plugin.getBountyHeadFormatter().buildHoverLabel(target.data()));
|
||||
stand.setCustomNameVisible(true);
|
||||
|
||||
});
|
||||
|
||||
activeLabels.put(target.key(), label);
|
||||
|
||||
}
|
||||
|
||||
private void removeLabel(HeadLabelKey key) {
|
||||
|
||||
final ArmorStand stand = activeLabels.remove(key);
|
||||
if (stand != null && stand.isValid()) {
|
||||
|
||||
stand.remove();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void clearLabels() {
|
||||
|
||||
final Set<HeadLabelKey> keys = new HashSet<>(activeLabels.keySet());
|
||||
keys.forEach(this::removeLabel);
|
||||
|
||||
}
|
||||
|
||||
private boolean isHoverModeEnabled() {
|
||||
|
||||
return StringUtils.equalsIgnoreCase(plugin.getConfig().getString("bounty-head-label-mode", "hover"), "hover");
|
||||
|
||||
}
|
||||
|
||||
private static boolean isHeadMaterial(Material material) {
|
||||
|
||||
return material == Material.PLAYER_HEAD || material == Material.PLAYER_WALL_HEAD;
|
||||
|
||||
}
|
||||
|
||||
private record HeadTarget(HeadLabelKey key, Location location, BountyHeadData data) {
|
||||
}
|
||||
|
||||
private record HeadLabelKey(UUID worldId, int x, int y, int z) {
|
||||
|
||||
private static HeadLabelKey fromBlock(Block block) {
|
||||
|
||||
final World world = block.getWorld();
|
||||
|
||||
return new HeadLabelKey(world.getUID(), block.getX(), block.getY(), block.getZ());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,13 +1,6 @@
|
||||
package com.tcoded.playerbountiesplus.listener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.Skull;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -23,38 +16,20 @@ import org.bukkit.event.player.PlayerItemHeldEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.inventory.meta.SkullMeta;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
|
||||
import com.tcoded.playerbountiesplus.PlayerBountiesOG;
|
||||
import com.tcoded.playerbountiesplus.hook.logging.CoreProtectHook;
|
||||
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.luckperms.api.LuckPerms;
|
||||
import net.luckperms.api.cacheddata.CachedMetaData;
|
||||
import net.luckperms.api.model.user.User;
|
||||
import net.trueog.diamondbankog.api.DiamondBankAPIJava;
|
||||
import net.trueog.utilitiesog.UtilitiesOG;
|
||||
import com.tcoded.playerbountiesplus.util.BountyHeadData;
|
||||
|
||||
public class BountyHeadListener implements Listener {
|
||||
|
||||
private final DiamondBankAPIJava diamondBankAPI;
|
||||
private final NamespacedKey targetKey;
|
||||
private final NamespacedKey targetUuidKey;
|
||||
private final NamespacedKey amountKey;
|
||||
private final LuckPerms luckPerms;
|
||||
private final PlayerBountiesOG plugin;
|
||||
private final CoreProtectHook coreProtectHook;
|
||||
|
||||
public BountyHeadListener(PlayerBountiesOG plugin, DiamondBankAPIJava diamondBankAPI, LuckPerms luckPerms,
|
||||
CoreProtectHook coreProtectHook)
|
||||
{
|
||||
public BountyHeadListener(PlayerBountiesOG plugin) {
|
||||
|
||||
this.diamondBankAPI = diamondBankAPI;
|
||||
this.targetKey = new NamespacedKey(plugin, DeathListener.BOUNTY_HEAD_NAME_KEY);
|
||||
this.targetUuidKey = new NamespacedKey(plugin, DeathListener.BOUNTY_HEAD_UUID_KEY);
|
||||
this.amountKey = new NamespacedKey(plugin, DeathListener.BOUNTY_HEAD_AMOUNT_KEY);
|
||||
this.luckPerms = luckPerms;
|
||||
this.coreProtectHook = coreProtectHook;
|
||||
this.plugin = plugin;
|
||||
this.coreProtectHook = plugin.getCoreProtectHook();
|
||||
|
||||
}
|
||||
|
||||
@@ -74,11 +49,8 @@ public class BountyHeadListener implements Listener {
|
||||
|
||||
}
|
||||
|
||||
final String targetName = itemMeta.getPersistentDataContainer().get(targetKey, PersistentDataType.STRING);
|
||||
final String targetUuid = itemMeta.getPersistentDataContainer().get(targetUuidKey, PersistentDataType.STRING);
|
||||
final Double bountyAmount = itemMeta.getPersistentDataContainer().get(amountKey, PersistentDataType.DOUBLE);
|
||||
|
||||
if (targetName == null || targetUuid == null || bountyAmount == null) {
|
||||
final BountyHeadData headData = plugin.getBountyHeadMetadata().read(itemMeta.getPersistentDataContainer());
|
||||
if (headData == null) {
|
||||
|
||||
return;
|
||||
|
||||
@@ -91,10 +63,7 @@ public class BountyHeadListener implements Listener {
|
||||
|
||||
}
|
||||
|
||||
final PersistentDataContainer blockData = skull.getPersistentDataContainer();
|
||||
blockData.set(targetKey, PersistentDataType.STRING, targetName);
|
||||
blockData.set(targetUuidKey, PersistentDataType.STRING, targetUuid);
|
||||
blockData.set(amountKey, PersistentDataType.DOUBLE, bountyAmount);
|
||||
plugin.getBountyHeadMetadata().write(skull.getPersistentDataContainer(), headData);
|
||||
skull.update(true, false);
|
||||
|
||||
if (this.coreProtectHook != null) {
|
||||
@@ -122,11 +91,8 @@ public class BountyHeadListener implements Listener {
|
||||
|
||||
}
|
||||
|
||||
final String targetName = skull.getPersistentDataContainer().get(targetKey, PersistentDataType.STRING);
|
||||
final String targetUuid = skull.getPersistentDataContainer().get(targetUuidKey, PersistentDataType.STRING);
|
||||
final Double bountyAmount = skull.getPersistentDataContainer().get(amountKey, PersistentDataType.DOUBLE);
|
||||
|
||||
if (targetName == null || targetUuid == null || bountyAmount == null) {
|
||||
final BountyHeadData headData = plugin.getBountyHeadMetadata().read(skull.getPersistentDataContainer());
|
||||
if (headData == null) {
|
||||
|
||||
return;
|
||||
|
||||
@@ -135,10 +101,8 @@ public class BountyHeadListener implements Listener {
|
||||
final ItemStack drop = new ItemStack(Material.PLAYER_HEAD, 1);
|
||||
final SkullMeta meta = (SkullMeta) drop.getItemMeta();
|
||||
|
||||
meta.setPlayerProfile(skull.getPlayerProfile());
|
||||
|
||||
applyBountyData(meta, targetName, targetUuid, bountyAmount);
|
||||
|
||||
plugin.getBountyHeadFormatter().applyHeadMeta(meta, headData, skull.getPlayerProfile(),
|
||||
plugin.getBountyHeadMetadata());
|
||||
drop.setItemMeta(meta);
|
||||
|
||||
if (this.coreProtectHook != null) {
|
||||
@@ -232,150 +196,16 @@ public class BountyHeadListener implements Listener {
|
||||
|
||||
}
|
||||
|
||||
private void sendBountyHeadActionbar(Player player, PersistentDataContainer dataContainer) {
|
||||
private void sendBountyHeadActionbar(Player player, org.bukkit.persistence.PersistentDataContainer dataContainer) {
|
||||
|
||||
final String targetName = dataContainer.get(targetKey, PersistentDataType.STRING);
|
||||
final String targetUuid = dataContainer.get(targetUuidKey, PersistentDataType.STRING);
|
||||
final Double bountyAmount = dataContainer.get(amountKey, PersistentDataType.DOUBLE);
|
||||
|
||||
if (targetName == null || targetUuid == null || bountyAmount == null) {
|
||||
final BountyHeadData headData = plugin.getBountyHeadMetadata().read(dataContainer);
|
||||
if (headData == null) {
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
final UUID uuid = parseUuid(targetUuid);
|
||||
final String playerDisplay = formatLuckPermsDisplay(uuid, targetName);
|
||||
final String diamonds = formatDiamonds(bountyAmount);
|
||||
player.sendActionBar(
|
||||
UtilitiesOG.trueogColorize("&c" + playerDisplay + "'s Head &7- &b" + diamonds + " &bDiamonds"));
|
||||
|
||||
}
|
||||
|
||||
private void applyBountyData(SkullMeta meta, String targetName, String targetUuid, double bountyAmount) {
|
||||
|
||||
meta.displayName(UtilitiesOG.trueogColorize("&c" + targetName + "'s Head"));
|
||||
|
||||
final UUID uuid = parseUuid(targetUuid);
|
||||
final String playerDisplay = formatLuckPermsDisplay(uuid, targetName);
|
||||
|
||||
final List<TextComponent> lore = new ArrayList<>();
|
||||
lore.add(UtilitiesOG.trueogColorize("&6Player: " + playerDisplay));
|
||||
lore.add(UtilitiesOG.trueogColorize("&cBeheaded for: &b" + formatDiamonds(bountyAmount) + " &bDiamonds"));
|
||||
meta.lore(lore);
|
||||
|
||||
meta.getPersistentDataContainer().set(targetKey, PersistentDataType.STRING, targetName);
|
||||
meta.getPersistentDataContainer().set(targetUuidKey, PersistentDataType.STRING, targetUuid);
|
||||
meta.getPersistentDataContainer().set(amountKey, PersistentDataType.DOUBLE, bountyAmount);
|
||||
|
||||
}
|
||||
|
||||
private UUID parseUuid(String uuidString) {
|
||||
|
||||
if (uuidString == null || uuidString.isBlank()) {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
return UUID.fromString(uuidString);
|
||||
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private String formatLuckPermsDisplay(UUID targetUuid, String fallbackName) {
|
||||
|
||||
final String playerName = StringUtils.defaultIfBlank(fallbackName, "Unknown Player");
|
||||
if (targetUuid == null || luckPerms == null) {
|
||||
|
||||
return "&f" + playerName;
|
||||
|
||||
}
|
||||
|
||||
final User user = luckPerms.getUserManager().getUser(targetUuid);
|
||||
if (user == null) {
|
||||
|
||||
return "&f" + playerName;
|
||||
|
||||
}
|
||||
|
||||
final CachedMetaData meta = user.getCachedData().getMetaData();
|
||||
final String prefix = StringUtils.trim(StringUtils.defaultString(meta.getPrefix()).replace('§', '&'));
|
||||
final String suffix = StringUtils.trim(StringUtils.defaultString(meta.getSuffix()).replace('§', '&'));
|
||||
final boolean metaContainsName = containsVisibleName(prefix, playerName)
|
||||
|| containsVisibleName(suffix, playerName);
|
||||
|
||||
final StringBuilder out = new StringBuilder();
|
||||
if (!prefix.isBlank()) {
|
||||
|
||||
out.append(prefix).append(' ');
|
||||
|
||||
}
|
||||
|
||||
if (!metaContainsName) {
|
||||
|
||||
out.append(playerName);
|
||||
|
||||
}
|
||||
|
||||
if (!suffix.isBlank()) {
|
||||
|
||||
out.append(' ').append(suffix);
|
||||
|
||||
}
|
||||
|
||||
return sanitizeDisplay(out.toString(), playerName);
|
||||
|
||||
}
|
||||
|
||||
private static String sanitizeDisplay(String formatted, String fallbackName) {
|
||||
|
||||
final String cleaned = StringUtils.trimToEmpty(formatted).replaceAll("(?i)(?:\\s*(?:<reset>|[&§]r))+$", "")
|
||||
.replaceAll("\\s*>$", "");
|
||||
|
||||
if (cleaned.isBlank()) {
|
||||
|
||||
return fallbackName;
|
||||
|
||||
}
|
||||
|
||||
return cleaned;
|
||||
|
||||
}
|
||||
|
||||
private static boolean containsVisibleName(String text, String playerName) {
|
||||
|
||||
if (text == null || playerName == null || playerName.isBlank()) {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
final String normalizedText = StringUtils.lowerCase(UtilitiesOG.stripFormatting(text), Locale.ROOT);
|
||||
final String normalizedName = StringUtils.lowerCase(playerName, Locale.ROOT);
|
||||
|
||||
return StringUtils.contains(normalizedText, normalizedName);
|
||||
|
||||
}
|
||||
|
||||
private String formatDiamonds(double diamonds) {
|
||||
|
||||
try {
|
||||
|
||||
return diamondBankAPI.shardsToDiamonds(diamondBankAPI.diamondsToShards(diamonds));
|
||||
|
||||
} catch (RuntimeException runtimeException) {
|
||||
|
||||
return String.valueOf(diamonds);
|
||||
|
||||
}
|
||||
player.sendActionBar(plugin.getBountyHeadFormatter().buildActionBar(headData));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import java.util.concurrent.ThreadLocalRandom;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -16,20 +15,16 @@ import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.SkullMeta;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
|
||||
import com.destroystokyo.paper.profile.PlayerProfile;
|
||||
import com.tcoded.playerbountiesplus.PlayerBountiesOG;
|
||||
import com.tcoded.playerbountiesplus.event.BountyClaimEvent;
|
||||
import com.tcoded.playerbountiesplus.hook.team.TeamHook;
|
||||
import com.tcoded.playerbountiesplus.manager.BountyDataManager;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import com.tcoded.playerbountiesplus.util.BountyHeadData;
|
||||
import net.luckperms.api.LuckPerms;
|
||||
import net.luckperms.api.cacheddata.CachedMetaData;
|
||||
import net.luckperms.api.model.user.User;
|
||||
import net.trueog.diamondbankog.api.DiamondBankAPIJava;
|
||||
import net.trueog.utilitiesog.UtilitiesOG;
|
||||
|
||||
public class DeathListener implements Listener {
|
||||
@@ -39,14 +34,12 @@ public class DeathListener implements Listener {
|
||||
public static final String BOUNTY_HEAD_AMOUNT_KEY = "bounty_head_diamonds";
|
||||
|
||||
private final PlayerBountiesOG plugin;
|
||||
private final DiamondBankAPIJava diamondBankAPI;
|
||||
private final LuckPerms luckPerms;
|
||||
|
||||
public DeathListener(PlayerBountiesOG plugin, DiamondBankAPIJava diamondBankAPI, LuckPerms luckPerms) {
|
||||
public DeathListener(PlayerBountiesOG plugin) {
|
||||
|
||||
this.plugin = plugin;
|
||||
this.diamondBankAPI = diamondBankAPI;
|
||||
this.luckPerms = luckPerms;
|
||||
this.luckPerms = plugin.getLuckPerms();
|
||||
|
||||
}
|
||||
|
||||
@@ -214,15 +207,7 @@ public class DeathListener implements Listener {
|
||||
|
||||
private String formatDiamonds(double diamonds) {
|
||||
|
||||
try {
|
||||
|
||||
return diamondBankAPI.shardsToDiamonds(diamondBankAPI.diamondsToShards(diamonds));
|
||||
|
||||
} catch (RuntimeException runtimeException) {
|
||||
|
||||
return String.valueOf(diamonds);
|
||||
|
||||
}
|
||||
return plugin.getBountyHeadFormatter().formatDiamonds(diamonds);
|
||||
|
||||
}
|
||||
|
||||
@@ -272,22 +257,10 @@ public class DeathListener implements Listener {
|
||||
|
||||
final ItemStack head = new ItemStack(Material.PLAYER_HEAD, 1);
|
||||
final SkullMeta headMeta = (SkullMeta) head.getItemMeta();
|
||||
final BountyHeadData headData = new BountyHeadData(victim.getUniqueId(), victim.getName(), bounty);
|
||||
|
||||
final PlayerProfile profile = Bukkit.createProfile(victim.getUniqueId());
|
||||
headMeta.setPlayerProfile(profile);
|
||||
headMeta.displayName(UtilitiesOG.trueogColorize("&c" + victim.getName() + "'s Head"));
|
||||
final String bountyDisplay = formatDiamonds(bounty);
|
||||
headMeta.lore(java.util.List.of(
|
||||
Component.text("Target: ", NamedTextColor.GRAY)
|
||||
.append(Component.text(victim.getName(), NamedTextColor.WHITE)),
|
||||
Component.text("Beheaded for: ", NamedTextColor.GRAY)
|
||||
.append(Component.text(bountyDisplay + " Diamonds", NamedTextColor.AQUA))));
|
||||
headMeta.getPersistentDataContainer().set(new NamespacedKey(plugin, BOUNTY_HEAD_NAME_KEY),
|
||||
PersistentDataType.STRING, victim.getName());
|
||||
headMeta.getPersistentDataContainer().set(new NamespacedKey(plugin, BOUNTY_HEAD_UUID_KEY),
|
||||
PersistentDataType.STRING, victim.getUniqueId().toString());
|
||||
headMeta.getPersistentDataContainer().set(new NamespacedKey(plugin, BOUNTY_HEAD_AMOUNT_KEY),
|
||||
PersistentDataType.DOUBLE, bounty);
|
||||
plugin.getBountyHeadFormatter().applyHeadMeta(headMeta, headData, profile, plugin.getBountyHeadMetadata());
|
||||
head.setItemMeta(headMeta);
|
||||
|
||||
event.getDrops().add(head);
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.tcoded.playerbountiesplus.util;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public record BountyHeadData(UUID targetUuid, String targetName, double bountyAmount) {
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
package com.tcoded.playerbountiesplus.util;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.bukkit.inventory.meta.SkullMeta;
|
||||
|
||||
import com.destroystokyo.paper.profile.PlayerProfile;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.luckperms.api.LuckPerms;
|
||||
import net.luckperms.api.cacheddata.CachedMetaData;
|
||||
import net.luckperms.api.model.user.User;
|
||||
import net.trueog.diamondbankog.api.DiamondBankAPIJava;
|
||||
import net.trueog.utilitiesog.UtilitiesOG;
|
||||
|
||||
public final class BountyHeadFormatter {
|
||||
|
||||
private final DiamondBankAPIJava diamondBankAPI;
|
||||
private final LuckPerms luckPerms;
|
||||
|
||||
public BountyHeadFormatter(DiamondBankAPIJava diamondBankAPI, LuckPerms luckPerms) {
|
||||
|
||||
this.diamondBankAPI = diamondBankAPI;
|
||||
this.luckPerms = luckPerms;
|
||||
|
||||
}
|
||||
|
||||
public void applyHeadMeta(SkullMeta meta, BountyHeadData data, PlayerProfile profile, BountyHeadMetadata metadata) {
|
||||
|
||||
if (profile != null) {
|
||||
|
||||
meta.setPlayerProfile(profile);
|
||||
|
||||
}
|
||||
|
||||
meta.displayName(buildHeadDisplayName(data));
|
||||
meta.lore(buildHeadLore(data));
|
||||
metadata.write(meta.getPersistentDataContainer(), data);
|
||||
|
||||
}
|
||||
|
||||
public TextComponent buildHeadDisplayName(BountyHeadData data) {
|
||||
|
||||
return UtilitiesOG
|
||||
.trueogColorize("&cBounty Head: &r" + resolvePlayerDisplay(data.targetUuid(), data.targetName()));
|
||||
|
||||
}
|
||||
|
||||
public List<TextComponent> buildHeadLore(BountyHeadData data) {
|
||||
|
||||
final String display = resolvePlayerDisplay(data.targetUuid(), data.targetName());
|
||||
final String bounty = formatDiamonds(data.bountyAmount());
|
||||
|
||||
return List.of(UtilitiesOG.trueogColorize("&6Target: " + display),
|
||||
UtilitiesOG.trueogColorize("&bBounty: &f" + bounty + " &bDiamonds"));
|
||||
|
||||
}
|
||||
|
||||
public TextComponent buildActionBar(BountyHeadData data) {
|
||||
|
||||
return UtilitiesOG
|
||||
.trueogColorize("&cBounty Head: &r" + resolvePlayerDisplay(data.targetUuid(), data.targetName())
|
||||
+ " &7- &b" + formatDiamonds(data.bountyAmount()) + " &bDiamonds");
|
||||
|
||||
}
|
||||
|
||||
public Component buildHoverLabel(BountyHeadData data) {
|
||||
|
||||
return UtilitiesOG.trueogColorize(resolvePlayerDisplay(data.targetUuid(), data.targetName()) + " &7- &b"
|
||||
+ formatDiamonds(data.bountyAmount()) + " &bDiamonds");
|
||||
|
||||
}
|
||||
|
||||
public String resolvePlayerDisplay(UUID targetUuid, String fallbackName) {
|
||||
|
||||
final String playerName = StringUtils.defaultIfBlank(fallbackName, "Unknown Player");
|
||||
if (targetUuid == null || luckPerms == null) {
|
||||
|
||||
return "&f" + playerName;
|
||||
|
||||
}
|
||||
|
||||
final User user = luckPerms.getUserManager().getUser(targetUuid);
|
||||
if (user == null) {
|
||||
|
||||
return "&f" + playerName;
|
||||
|
||||
}
|
||||
|
||||
final CachedMetaData meta = user.getCachedData().getMetaData();
|
||||
final String prefix = StringUtils.trim(StringUtils.defaultString(meta.getPrefix()).replace('§', '&'));
|
||||
final String suffix = StringUtils.trim(StringUtils.defaultString(meta.getSuffix()).replace('§', '&'));
|
||||
final boolean metaContainsName = containsVisibleName(prefix, playerName)
|
||||
|| containsVisibleName(suffix, playerName);
|
||||
|
||||
final StringBuilder out = new StringBuilder();
|
||||
if (!prefix.isBlank()) {
|
||||
|
||||
out.append(prefix).append(' ');
|
||||
|
||||
}
|
||||
|
||||
if (!metaContainsName) {
|
||||
|
||||
out.append(playerName);
|
||||
|
||||
}
|
||||
|
||||
if (!suffix.isBlank()) {
|
||||
|
||||
out.append(' ').append(suffix);
|
||||
|
||||
}
|
||||
|
||||
return sanitizeDisplay(out.toString(), playerName);
|
||||
|
||||
}
|
||||
|
||||
public String formatDiamonds(double diamonds) {
|
||||
|
||||
if (diamondBankAPI == null) {
|
||||
|
||||
return String.valueOf(diamonds);
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
return diamondBankAPI.shardsToDiamonds(diamondBankAPI.diamondsToShards(diamonds));
|
||||
|
||||
} catch (RuntimeException runtimeException) {
|
||||
|
||||
return String.valueOf(diamonds);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static String sanitizeDisplay(String formatted, String fallbackName) {
|
||||
|
||||
final String cleaned = StringUtils.trimToEmpty(formatted).replaceAll("(?i)(?:\\s*(?:<reset>|[&§]r))+$", "")
|
||||
.replaceAll("\\s*>$", "");
|
||||
|
||||
return cleaned.isBlank() ? fallbackName : cleaned;
|
||||
|
||||
}
|
||||
|
||||
private static boolean containsVisibleName(String text, String playerName) {
|
||||
|
||||
if (text == null || playerName == null || playerName.isBlank()) {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
final String normalizedText = StringUtils.lowerCase(UtilitiesOG.stripFormatting(text), Locale.ROOT);
|
||||
final String normalizedName = StringUtils.lowerCase(playerName, Locale.ROOT);
|
||||
|
||||
return StringUtils.contains(normalizedText, normalizedName);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.tcoded.playerbountiesplus.util;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
|
||||
import com.tcoded.playerbountiesplus.PlayerBountiesOG;
|
||||
import com.tcoded.playerbountiesplus.listener.DeathListener;
|
||||
|
||||
public final class BountyHeadMetadata {
|
||||
|
||||
private final NamespacedKey targetKey;
|
||||
private final NamespacedKey targetUuidKey;
|
||||
private final NamespacedKey amountKey;
|
||||
|
||||
public BountyHeadMetadata(PlayerBountiesOG plugin) {
|
||||
|
||||
this.targetKey = new NamespacedKey(plugin, DeathListener.BOUNTY_HEAD_NAME_KEY);
|
||||
this.targetUuidKey = new NamespacedKey(plugin, DeathListener.BOUNTY_HEAD_UUID_KEY);
|
||||
this.amountKey = new NamespacedKey(plugin, DeathListener.BOUNTY_HEAD_AMOUNT_KEY);
|
||||
|
||||
}
|
||||
|
||||
public BountyHeadData read(PersistentDataContainer dataContainer) {
|
||||
|
||||
final String targetName = dataContainer.get(targetKey, PersistentDataType.STRING);
|
||||
final String targetUuid = dataContainer.get(targetUuidKey, PersistentDataType.STRING);
|
||||
final Double bountyAmount = dataContainer.get(amountKey, PersistentDataType.DOUBLE);
|
||||
|
||||
if (StringUtils.isBlank(targetName) || StringUtils.isBlank(targetUuid) || bountyAmount == null) {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
return new BountyHeadData(UUID.fromString(targetUuid), targetName, bountyAmount);
|
||||
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void write(PersistentDataContainer dataContainer, BountyHeadData data) {
|
||||
|
||||
dataContainer.set(targetKey, PersistentDataType.STRING, data.targetName());
|
||||
dataContainer.set(targetUuidKey, PersistentDataType.STRING, data.targetUuid().toString());
|
||||
dataContainer.set(amountKey, PersistentDataType.DOUBLE, data.bountyAmount());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,6 +36,14 @@ bounty-claimed-announce: true
|
||||
# Chance (0-100) that claiming a bounty drops the victim's player head.
|
||||
bounty-head-drop-chance: 50.0
|
||||
|
||||
# How placed bounty heads should display extra labels.
|
||||
# none = disabled
|
||||
# hover = show a temporary floating label while a player aims at the head
|
||||
bounty-head-label-mode: hover
|
||||
|
||||
# Maximum range in blocks for detecting a looked-at bounty head.
|
||||
bounty-head-label-range: 8.0
|
||||
|
||||
# If we should announce that the bounty was placed.
|
||||
bounty-placed-announce: true
|
||||
|
||||
|
||||
Reference in new issue
Block a user