337 lines
15 KiB
Java
337 lines
15 KiB
Java
package world.bentobox.bentobox.managers;
|
|
|
|
import java.util.Arrays;
|
|
import java.util.Optional;
|
|
import java.util.UUID;
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
import java.util.stream.Collectors;
|
|
import java.util.stream.IntStream;
|
|
|
|
import org.bukkit.Bukkit;
|
|
import org.bukkit.OfflinePlayer;
|
|
import org.bukkit.entity.Player;
|
|
import org.eclipse.jdt.annotation.NonNull;
|
|
import org.eclipse.jdt.annotation.Nullable;
|
|
|
|
import world.bentobox.bentobox.BentoBox;
|
|
import world.bentobox.bentobox.api.addons.Addon;
|
|
import world.bentobox.bentobox.api.addons.GameModeAddon;
|
|
import world.bentobox.bentobox.api.localization.TextVariables;
|
|
import world.bentobox.bentobox.api.placeholders.PlaceholderReplacer;
|
|
import world.bentobox.bentobox.api.user.User;
|
|
import world.bentobox.bentobox.database.objects.Island;
|
|
import world.bentobox.bentobox.hooks.placeholders.PlaceholderAPIHook;
|
|
import world.bentobox.bentobox.lists.GameModePlaceholder;
|
|
|
|
/**
|
|
* Manages placeholder integration.
|
|
*
|
|
* @author Poslovitch
|
|
*/
|
|
public class PlaceholdersManager {
|
|
|
|
private static final int MAX_TEAM_MEMBER_PLACEHOLDERS = 50;
|
|
private final BentoBox plugin;
|
|
|
|
public PlaceholdersManager(BentoBox plugin) {
|
|
this.plugin = plugin;
|
|
}
|
|
|
|
/**
|
|
* Registers this placeholder on the behalf of BentoBox.
|
|
* @param placeholder the placeholder to register, not null.
|
|
* It will be appended with {@code "bentobox_"} by the placeholder plugin.
|
|
* @param replacer the expression that will return a {@code String} when executed, which will be this placeholder's replacement.
|
|
*/
|
|
public void registerPlaceholder(@NonNull String placeholder, @NonNull PlaceholderReplacer replacer) {
|
|
// Register it in PlaceholderAPI
|
|
getPlaceholderAPIHook().ifPresent(hook -> hook.registerPlaceholder(placeholder, replacer));
|
|
}
|
|
|
|
/**
|
|
* Registers this placeholder on the behalf of the specified addon.
|
|
* @param addon the addon to register this placeholder on its behalf.
|
|
* If null, the placeholder will be registered using {@link #registerPlaceholder(String, PlaceholderReplacer)}.
|
|
* @param placeholder the placeholder to register, not null.
|
|
* It will be appended with the addon's name by the placeholder plugin.
|
|
* @param replacer the expression that will return a {@code String} when executed, which will replace the placeholder.
|
|
*/
|
|
public void registerPlaceholder(@Nullable Addon addon, @NonNull String placeholder, @NonNull PlaceholderReplacer replacer) {
|
|
if (addon == null) {
|
|
registerPlaceholder(placeholder, replacer);
|
|
return;
|
|
}
|
|
// Register it in PlaceholderAPI
|
|
getPlaceholderAPIHook().ifPresent(hook -> hook.registerPlaceholder(addon, placeholder, replacer));
|
|
}
|
|
|
|
/**
|
|
* Registers default placeholders for this gamemode addon.
|
|
* @param addon the gamemode addon to register the default placeholders too.
|
|
* @since 1.5.0
|
|
*/
|
|
public void registerDefaultPlaceholders(@NonNull GameModeAddon addon) {
|
|
Arrays.stream(GameModePlaceholder.values())
|
|
.filter(placeholder -> !isPlaceholder(addon, placeholder.getPlaceholder()))
|
|
.forEach(placeholder -> registerPlaceholder(addon, placeholder.getPlaceholder(), new DefaultPlaceholder(addon, placeholder)));
|
|
// Register team member placeholders
|
|
registerTeamMemberPlaceholders(addon);
|
|
// Register potential island names and member info
|
|
registerOwnedIslandPlaceholders(addon);
|
|
}
|
|
|
|
private void registerOwnedIslandPlaceholders(@NonNull GameModeAddon addon) {
|
|
int maxIslands = plugin.getIWM().getWorldSettings(addon.getOverWorld()).getConcurrentIslands();
|
|
IntStream.range(0, maxIslands).forEach(i -> registerPlaceholder(addon, "island_name_" + (i + 1), user -> {
|
|
if (user == null)
|
|
return "";
|
|
|
|
AtomicInteger generatedCount = new AtomicInteger(1); // To increment within lambda
|
|
return plugin.getIslands().getIslands(addon.getOverWorld(), user).stream().map(island -> {
|
|
IslandName islandName = getIslandName(island, user, generatedCount.get());
|
|
if (islandName.generatated()) {
|
|
generatedCount.getAndIncrement(); // Increment if the name was generated
|
|
}
|
|
return islandName.name;
|
|
}).skip(i) // Skip to the island at index 'i'
|
|
.findFirst() // Take the first island after skipping, effectively the (i+1)th
|
|
.orElse(""); // Default to empty string if no island is found
|
|
}));
|
|
|
|
// Island_memberlist
|
|
IntStream.range(0, maxIslands)
|
|
.forEach(i -> registerPlaceholder(addon, "island_memberlist_" + (i + 1), user -> user == null ? ""
|
|
: plugin.getIslands().getIslands(addon.getOverWorld(), user).stream().skip(i).findFirst()
|
|
.map(island -> island.getMemberSet().stream()
|
|
.map(addon.getPlayers()::getName).collect(Collectors.joining(",")))
|
|
.orElse("")));
|
|
}
|
|
|
|
private record IslandName(String name, boolean generatated) {
|
|
}
|
|
|
|
private IslandName getIslandName(Island island, User user, int index) {
|
|
if (island.getName() != null && !island.getName().isBlank()) {
|
|
// Name has been set
|
|
return new IslandName(island.getName(), false);
|
|
} else {
|
|
// Name has not been set
|
|
return new IslandName(user.getTranslation("protection.flags.ENTER_EXIT_MESSAGES.island", TextVariables.NAME,
|
|
user.getName(), TextVariables.DISPLAY_NAME, user.getDisplayName()) + " " + index, true);
|
|
}
|
|
|
|
}
|
|
|
|
private void registerTeamMemberPlaceholders(@NonNull GameModeAddon addon) {
|
|
for (int i = 1; i <= MAX_TEAM_MEMBER_PLACEHOLDERS; i++) {
|
|
final int count = i;
|
|
// Names
|
|
registerPlaceholder(addon, "island_member_name_" + i, user -> {
|
|
if (user != null) {
|
|
Island island = plugin.getIslands().getIsland(addon.getOverWorld(), user);
|
|
int j = 1;
|
|
for (UUID uuid : island.getMemberSet(RanksManager.MEMBER_RANK)) {
|
|
if (j++ == count) {
|
|
return plugin.getPlayers().getName(uuid);
|
|
}
|
|
}
|
|
}
|
|
return "";
|
|
});
|
|
// Register ranks
|
|
registerPlaceholder(addon, "island_member_rank_" + i, user -> {
|
|
if (user != null) {
|
|
Island island = plugin.getIslands().getIsland(addon.getOverWorld(), user);
|
|
int j = 1;
|
|
for (UUID uuid : island.getMemberSet(RanksManager.MEMBER_RANK)) {
|
|
if (j++ == count) {
|
|
return user.getTranslationOrNothing(RanksManager.getInstance().getRank(island.getRank(uuid)));
|
|
}
|
|
}
|
|
}
|
|
return "";
|
|
});
|
|
// Banned
|
|
registerPlaceholder(addon, "island_banned_name_" + i, user -> {
|
|
if (user != null) {
|
|
Island island = plugin.getIslands().getIsland(addon.getOverWorld(), user);
|
|
int j = 1;
|
|
for (UUID uuid : island.getBanned()) {
|
|
if (j++ == count) {
|
|
return plugin.getPlayers().getName(uuid);
|
|
}
|
|
}
|
|
}
|
|
return "";
|
|
});
|
|
// Visited Island
|
|
registerPlaceholder(addon, "visited_island_member_name_" + i, user -> {
|
|
if (user != null) {
|
|
return plugin.getIslands().getIslandAt(user.getLocation())
|
|
.filter(island -> addon.inWorld(island.getCenter()))
|
|
.map(island -> {
|
|
int j = 1;
|
|
for (UUID uuid : island.getMemberSet(RanksManager.MEMBER_RANK)) {
|
|
if (j++ == count) {
|
|
return plugin.getPlayers().getName(uuid);
|
|
}
|
|
}
|
|
return "";
|
|
}).orElse("");
|
|
|
|
}
|
|
return "";
|
|
});
|
|
registerPlaceholder(addon, "visited_island_member_rank_" + i, user -> {
|
|
if (user != null) {
|
|
return plugin.getIslands().getIslandAt(user.getLocation())
|
|
.filter(island -> addon.inWorld(island.getCenter()))
|
|
.map(island -> {
|
|
int j = 1;
|
|
for (UUID uuid : island.getMemberSet(RanksManager.MEMBER_RANK)) {
|
|
if (j++ == count) {
|
|
return user.getTranslationOrNothing(RanksManager.getInstance().getRank(island.getRank(uuid)));
|
|
}
|
|
}
|
|
return "";
|
|
}).orElse("");
|
|
|
|
}
|
|
return "";
|
|
});
|
|
registerPlaceholder(addon, "visited_island_banned_name_" + i, user -> {
|
|
if (user != null) {
|
|
return plugin.getIslands().getIslandAt(user.getLocation())
|
|
.filter(island -> addon.inWorld(island.getCenter()))
|
|
.map(island -> {
|
|
int j = 1;
|
|
for (UUID uuid : island.getBanned()) {
|
|
if (j++ == count) {
|
|
return plugin.getPlayers().getName(uuid);
|
|
}
|
|
}
|
|
return "";
|
|
}).orElse("");
|
|
|
|
}
|
|
return "";
|
|
});
|
|
}
|
|
// Counts
|
|
// Number of online members
|
|
// {@since 2.1.0}
|
|
registerPlaceholder(addon, "island_online_members_count", user -> {
|
|
if (user == null)
|
|
return "";
|
|
Island island = plugin.getIslands().getIsland(addon.getOverWorld(), user);
|
|
return island != null
|
|
? String.valueOf(island.getMemberSet(RanksManager.MEMBER_RANK).stream()
|
|
.map(Bukkit::getOfflinePlayer).filter(OfflinePlayer::isOnline).count())
|
|
: "";
|
|
});
|
|
// Number of online members of visited island
|
|
registerPlaceholder(addon, "visited_island_online_members_count", user -> {
|
|
if (user == null)
|
|
return "";
|
|
return plugin.getIslands().getIslandAt(user.getLocation())
|
|
.map(island -> String.valueOf(island.getMemberSet(RanksManager.MEMBER_RANK).stream()
|
|
.map(Bukkit::getOfflinePlayer).filter(OfflinePlayer::isOnline).count()))
|
|
.orElse("");
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Unregisters this placeholder on the behalf of BentoBox.
|
|
* Note that if the placeholder you are trying to unregister has been registered by an addon, you should use {@link #unregisterPlaceholder(Addon, String)} instead.
|
|
* @param placeholder the placeholder to unregister, not null.
|
|
* @since 1.4.0
|
|
*/
|
|
public void unregisterPlaceholder(@NonNull String placeholder) {
|
|
// Unregister it from PlaceholderAPI
|
|
getPlaceholderAPIHook().ifPresent(hook -> hook.unregisterPlaceholder(placeholder));
|
|
}
|
|
|
|
/**
|
|
* Unregisters this placeholder on the behalf of the specified addon.
|
|
* @param addon the addon that originally registered this placeholder.
|
|
* If null, this placeholder will be unregistered using {@link #unregisterPlaceholder(String)}.
|
|
* @param placeholder the placeholder to unregister, not null.
|
|
* @since 1.4.0
|
|
*/
|
|
public void unregisterPlaceholder(@Nullable Addon addon, @NonNull String placeholder) {
|
|
if (addon == null) {
|
|
unregisterPlaceholder(placeholder);
|
|
return;
|
|
}
|
|
// Unregister it from PlaceholderAPI
|
|
getPlaceholderAPIHook().ifPresent(hook -> hook.unregisterPlaceholder(addon, placeholder));
|
|
}
|
|
|
|
/**
|
|
* Returns an Optional containing the PlaceholderAPIHook instance, or an empty Optional otherwise.
|
|
* @return Optional containing the PlaceholderAPIHook instance or an empty Optional otherwise.
|
|
* @since 1.4.0
|
|
*/
|
|
@NonNull
|
|
private Optional<PlaceholderAPIHook> getPlaceholderAPIHook() {
|
|
return plugin.getHooks().getHook("PlaceholderAPI").map(PlaceholderAPIHook.class::cast);
|
|
}
|
|
|
|
/**
|
|
* Checks if a placeholder with this name is already registered
|
|
* @param addon the addon, not null
|
|
* @param placeholder - name of placeholder
|
|
* @return {@code true} if a placeholder with this name is already registered
|
|
* @since 1.4.0
|
|
*/
|
|
public boolean isPlaceholder(@NonNull Addon addon, @NonNull String placeholder) {
|
|
return getPlaceholderAPIHook().map(h -> h.isPlaceholder(addon, placeholder)).orElse(false);
|
|
}
|
|
|
|
/**
|
|
* Replaces the placeholders in this String and returns it.
|
|
* @param player the Player to get the placeholders for or null for non-player-specific placeholders
|
|
* @param string the String to replace the placeholders in.
|
|
* @return the String with placeholders replaced, or the identical String if no placeholders were available.
|
|
* @since 1.5.0
|
|
*/
|
|
public String replacePlaceholders(@Nullable Player player, @NonNull String string) {
|
|
return getPlaceholderAPIHook().map(papi -> papi.replacePlaceholders(player, string)).orElse(string);
|
|
}
|
|
|
|
/**
|
|
* Unregisters all the placeholders.
|
|
* @since 1.15.0
|
|
*/
|
|
public void unregisterAll() {
|
|
getPlaceholderAPIHook().ifPresent(PlaceholderAPIHook::unregisterAll);
|
|
|
|
}
|
|
|
|
/**
|
|
* Default placeholder
|
|
*
|
|
*/
|
|
class DefaultPlaceholder implements PlaceholderReplacer {
|
|
private final GameModeAddon addon;
|
|
private final GameModePlaceholder type;
|
|
public DefaultPlaceholder(GameModeAddon addon, GameModePlaceholder type) {
|
|
this.addon = addon;
|
|
this.type = type;
|
|
}
|
|
/* (non-Javadoc)
|
|
* @see world.bentobox.bentobox.api.placeholders.PlaceholderReplacer#onReplace(world.bentobox.bentobox.api.user.User)
|
|
*/
|
|
@NonNull
|
|
@Override
|
|
public String onReplace(@Nullable User user) {
|
|
if (user == null) {
|
|
return "";
|
|
}
|
|
Island island = addon.getIslands().getIsland(addon.getOverWorld(), user);
|
|
|
|
return type.getReplacer().onReplace(addon, user, island);
|
|
}
|
|
}
|
|
}
|