mirror of
https://github.com/DiscordSRV/Ascension.git
synced 2024-12-01 13:23:59 +01:00
Add PlaceholderAPI (Bukkit) support
This commit is contained in:
parent
5ccf8f7cb7
commit
3f030dfada
@ -52,10 +52,11 @@ public class PlaceholderLookupEvent implements Event, Processable {
|
|||||||
return contexts;
|
return contexts;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<Object> getContext(Class<?> type) {
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> Optional<T> getContext(Class<T> type) {
|
||||||
for (Object o : contexts) {
|
for (Object o : contexts) {
|
||||||
if (type.isAssignableFrom(o.getClass())) {
|
if (type.isAssignableFrom(o.getClass())) {
|
||||||
return Optional.of(o);
|
return Optional.of((T) o);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
|
@ -25,6 +25,7 @@ package com.discordsrv.api.placeholder;
|
|||||||
|
|
||||||
import com.discordsrv.api.placeholder.mapper.PlaceholderResultMapper;
|
import com.discordsrv.api.placeholder.mapper.PlaceholderResultMapper;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
@ -52,6 +53,9 @@ public interface PlaceholderService {
|
|||||||
PlaceholderLookupResult lookupPlaceholder(@NotNull String placeholder, @NotNull Object... context);
|
PlaceholderLookupResult lookupPlaceholder(@NotNull String placeholder, @NotNull Object... context);
|
||||||
|
|
||||||
Object getResult(@NotNull Matcher matcher, @NotNull Set<Object> context);
|
Object getResult(@NotNull Matcher matcher, @NotNull Set<Object> context);
|
||||||
|
@NotNull
|
||||||
CharSequence getResultAsPlain(@NotNull Matcher matcher, @NotNull Set<Object> context);
|
CharSequence getResultAsPlain(@NotNull Matcher matcher, @NotNull Set<Object> context);
|
||||||
|
@NotNull
|
||||||
|
CharSequence getResultAsPlain(@Nullable Object result);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
|
|
||||||
package com.discordsrv.api.player;
|
package com.discordsrv.api.player;
|
||||||
|
|
||||||
import com.discordsrv.api.placeholder.annotation.Placeholder;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@ -37,7 +36,6 @@ public interface DiscordSRVPlayer {
|
|||||||
* The username of the player.
|
* The username of the player.
|
||||||
* @return the player's username
|
* @return the player's username
|
||||||
*/
|
*/
|
||||||
@Placeholder("player_name")
|
|
||||||
@NotNull
|
@NotNull
|
||||||
String username();
|
String username();
|
||||||
|
|
||||||
@ -45,7 +43,6 @@ public interface DiscordSRVPlayer {
|
|||||||
* The {@link UUID} of the player.
|
* The {@link UUID} of the player.
|
||||||
* @return the player's unique id
|
* @return the player's unique id
|
||||||
*/
|
*/
|
||||||
@Placeholder("player_uuid")
|
|
||||||
@NotNull
|
@NotNull
|
||||||
UUID uniqueId();
|
UUID uniqueId();
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@ allprojects {
|
|||||||
}
|
}
|
||||||
filter {
|
filter {
|
||||||
includeGroup 'net.milkbowl.vault'
|
includeGroup 'net.milkbowl.vault'
|
||||||
|
includeGroup 'me.clip'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,6 +80,7 @@ dependencies {
|
|||||||
|
|
||||||
// Integrations
|
// Integrations
|
||||||
compileOnly(libs.vaultapi)
|
compileOnly(libs.vaultapi)
|
||||||
|
compileOnly(libs.placeholderapi.bukkit)
|
||||||
}
|
}
|
||||||
|
|
||||||
processResources {
|
processResources {
|
||||||
|
@ -225,6 +225,7 @@ public class BukkitDiscordSRV extends ServerDiscordSRV<DiscordSRVBukkitBootstrap
|
|||||||
|
|
||||||
// Integrations
|
// Integrations
|
||||||
registerIntegration("com.discordsrv.bukkit.integration.VaultIntegration");
|
registerIntegration("com.discordsrv.bukkit.integration.VaultIntegration");
|
||||||
|
registerIntegration("com.discordsrv.bukkit.integration.PlaceholderAPIIntegration");
|
||||||
|
|
||||||
super.enable();
|
super.enable();
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ public class DiscordSRVBukkitBootstrap extends BukkitBootstrap implements IBoots
|
|||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
private final LifecycleManager lifecycleManager;
|
private final LifecycleManager lifecycleManager;
|
||||||
private BukkitDiscordSRV discordSRV;
|
private BukkitDiscordSRV discordSRV;
|
||||||
|
private final List<Runnable> mainThreadTasksForDisable = new ArrayList<>();
|
||||||
|
|
||||||
public DiscordSRVBukkitBootstrap(JarInJarClassLoader classLoader, JavaPlugin plugin) throws IOException {
|
public DiscordSRVBukkitBootstrap(JarInJarClassLoader classLoader, JavaPlugin plugin) throws IOException {
|
||||||
// Don't change these parameters
|
// Don't change these parameters
|
||||||
@ -73,6 +74,11 @@ public class DiscordSRVBukkitBootstrap extends BukkitBootstrap implements IBoots
|
|||||||
@Override
|
@Override
|
||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
lifecycleManager.disable(discordSRV);
|
lifecycleManager.disable(discordSRV);
|
||||||
|
|
||||||
|
// Run tasks on the main thread (scheduler cannot be used when disabling)
|
||||||
|
for (Runnable runnable : mainThreadTasksForDisable) {
|
||||||
|
runnable.run();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -94,4 +100,8 @@ public class DiscordSRVBukkitBootstrap extends BukkitBootstrap implements IBoots
|
|||||||
public Path dataDirectory() {
|
public Path dataDirectory() {
|
||||||
return getPlugin().getDataFolder().toPath();
|
return getPlugin().getDataFolder().toPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Runnable> mainThreadTasksForDisable() {
|
||||||
|
return mainThreadTasksForDisable;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,155 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of DiscordSRV, licensed under the GPLv3 License
|
||||||
|
* Copyright (c) 2016-2022 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.discordsrv.bukkit.integration;
|
||||||
|
|
||||||
|
import com.discordsrv.api.event.bus.Subscribe;
|
||||||
|
import com.discordsrv.api.event.events.placeholder.PlaceholderLookupEvent;
|
||||||
|
import com.discordsrv.api.placeholder.PlaceholderLookupResult;
|
||||||
|
import com.discordsrv.api.player.DiscordSRVPlayer;
|
||||||
|
import com.discordsrv.api.profile.IProfile;
|
||||||
|
import com.discordsrv.bukkit.BukkitDiscordSRV;
|
||||||
|
import com.discordsrv.common.module.type.PluginIntegration;
|
||||||
|
import com.discordsrv.common.player.IOfflinePlayer;
|
||||||
|
import me.clip.placeholderapi.PlaceholderAPI;
|
||||||
|
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class PlaceholderAPIIntegration extends PluginIntegration<BukkitDiscordSRV> {
|
||||||
|
|
||||||
|
private static final String OPTIONAL_PREFIX = "placeholderapi_";
|
||||||
|
private Expansion expansion;
|
||||||
|
|
||||||
|
public PlaceholderAPIIntegration(BukkitDiscordSRV discordSRV) {
|
||||||
|
super(discordSRV);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled() {
|
||||||
|
try {
|
||||||
|
Class.forName("me.clip.placeholderapi.PlaceholderAPI");
|
||||||
|
} catch (ClassNotFoundException ignored) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.isEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void enable() {
|
||||||
|
expansion = new Expansion();
|
||||||
|
discordSRV.scheduler().runOnMainThread(() -> expansion.register());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void disable() {
|
||||||
|
if (expansion != null) {
|
||||||
|
discordSRV.scheduler().runOnMainThread(() -> expansion.unregister());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onPlaceholderLookup(PlaceholderLookupEvent event) {
|
||||||
|
String placeholder = event.getPlaceholder();
|
||||||
|
if (placeholder.startsWith(OPTIONAL_PREFIX)) {
|
||||||
|
placeholder = placeholder.substring(OPTIONAL_PREFIX.length());
|
||||||
|
}
|
||||||
|
placeholder = "%" + placeholder + "%";
|
||||||
|
|
||||||
|
Player player = event.getContext(DiscordSRVPlayer.class)
|
||||||
|
.map(p -> discordSRV.server().getPlayer(p.uniqueId()))
|
||||||
|
.orElse(null);
|
||||||
|
if (player != null) {
|
||||||
|
setResult(event, placeholder, PlaceholderAPI.setPlaceholders(player, placeholder));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UUID uuid = event.getContext(IProfile.class)
|
||||||
|
.flatMap(IProfile::playerUUID)
|
||||||
|
.orElseGet(() -> event.getContext(IOfflinePlayer.class).map(IOfflinePlayer::uniqueId).orElse(null));
|
||||||
|
|
||||||
|
OfflinePlayer offlinePlayer = uuid != null ? discordSRV.server().getOfflinePlayer(uuid) : null;
|
||||||
|
setResult(event, placeholder, PlaceholderAPI.setPlaceholders(offlinePlayer, placeholder));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setResult(PlaceholderLookupEvent event, String placeholder, String result) {
|
||||||
|
if (result.equals(placeholder)) {
|
||||||
|
// Didn't resolve
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.process(PlaceholderLookupResult.success(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Expansion extends PlaceholderExpansion {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull String getIdentifier() {
|
||||||
|
return "discordsrv";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull String getAuthor() {
|
||||||
|
return "DiscordSRV";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull String getVersion() {
|
||||||
|
return discordSRV.version();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull String getName() {
|
||||||
|
return "DiscordSRV";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean persist() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable String onPlaceholderRequest(Player player, @NotNull String params) {
|
||||||
|
return onRequest(player, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable String onRequest(OfflinePlayer player, @NotNull String params) {
|
||||||
|
Set<Object> context;
|
||||||
|
if (player != null) {
|
||||||
|
context = new HashSet<>(2);
|
||||||
|
discordSRV.profileManager().getProfile(player.getUniqueId()).ifPresent(context::add);
|
||||||
|
if (player instanceof Player) {
|
||||||
|
context.add(discordSRV.playerProvider().player((Player) player));
|
||||||
|
} else {
|
||||||
|
context.add(discordSRV.playerProvider().offlinePlayer(player));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
context = Collections.emptySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
String placeholder = "%" + params + "%";
|
||||||
|
return discordSRV.placeholderService().replacePlaceholders(placeholder, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -19,8 +19,13 @@
|
|||||||
package com.discordsrv.bukkit.scheduler;
|
package com.discordsrv.bukkit.scheduler;
|
||||||
|
|
||||||
import com.discordsrv.bukkit.BukkitDiscordSRV;
|
import com.discordsrv.bukkit.BukkitDiscordSRV;
|
||||||
import com.discordsrv.common.server.scheduler.ServerScheduler;
|
import com.discordsrv.bukkit.DiscordSRVBukkitBootstrap;
|
||||||
|
import com.discordsrv.common.DiscordSRV;
|
||||||
import com.discordsrv.common.scheduler.StandardScheduler;
|
import com.discordsrv.common.scheduler.StandardScheduler;
|
||||||
|
import com.discordsrv.common.server.scheduler.ServerScheduler;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
public class BukkitScheduler extends StandardScheduler implements ServerScheduler {
|
public class BukkitScheduler extends StandardScheduler implements ServerScheduler {
|
||||||
|
|
||||||
@ -31,18 +36,28 @@ public class BukkitScheduler extends StandardScheduler implements ServerSchedule
|
|||||||
this.discordSRV = discordSRV;
|
this.discordSRV = discordSRV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkDisable(Runnable task, BiConsumer<org.bukkit.scheduler.BukkitScheduler, Plugin> runNormal) {
|
||||||
|
// Can't run tasks when disabling, so we'll push those to the bootstrap to run after disable
|
||||||
|
if (!discordSRV.plugin().isEnabled() && discordSRV.status() == DiscordSRV.Status.SHUTTING_DOWN) {
|
||||||
|
((DiscordSRVBukkitBootstrap) discordSRV.bootstrap()).mainThreadTasksForDisable().add(task);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
runNormal.accept(discordSRV.server().getScheduler(), discordSRV.plugin());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void runOnMainThread(Runnable task) {
|
public void runOnMainThread(Runnable task) {
|
||||||
discordSRV.server().getScheduler().runTask(discordSRV.plugin(), task);
|
checkDisable(task, (scheduler, plugin) -> scheduler.runTask(plugin, task));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void runOnMainThreadLaterInTicks(Runnable task, int ticks) {
|
public void runOnMainThreadLaterInTicks(Runnable task, int ticks) {
|
||||||
discordSRV.server().getScheduler().runTaskLater(discordSRV.plugin(), task, ticks);
|
checkDisable(task, (scheduler, plugin) -> scheduler.runTaskLater(plugin, task, ticks));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void runOnMainThreadAtFixedRateInTicks(Runnable task, int initialTicks, int rateTicks) {
|
public void runOnMainThreadAtFixedRateInTicks(Runnable task, int initialTicks, int rateTicks) {
|
||||||
discordSRV.server().getScheduler().runTaskTimer(discordSRV.plugin(), task, initialTicks, rateTicks);
|
checkDisable(task, (scheduler, plugin) -> scheduler.runTaskTimer(plugin, task, initialTicks, rateTicks));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -175,12 +175,13 @@ public class PlaceholderServiceImpl implements PlaceholderService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CharSequence getResultAsPlain(@NotNull Matcher matcher, @NotNull Set<Object> context) {
|
public @NotNull CharSequence getResultAsPlain(@NotNull Matcher matcher, @NotNull Set<Object> context) {
|
||||||
Object result = getResult(matcher, context);
|
Object result = getResult(matcher, context);
|
||||||
return getResultAsPlain(result);
|
return getResultAsPlain(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CharSequence getResultAsPlain(Object result) {
|
@Override
|
||||||
|
public @NotNull CharSequence getResultAsPlain(@Nullable Object result) {
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
return "";
|
return "";
|
||||||
} else if (result instanceof CharSequence) {
|
} else if (result instanceof CharSequence) {
|
||||||
@ -214,10 +215,6 @@ public class PlaceholderServiceImpl implements PlaceholderService {
|
|||||||
Object representation = getResultRepresentation(results, placeholder, matcher);
|
Object representation = getResultRepresentation(results, placeholder, matcher);
|
||||||
|
|
||||||
CharSequence output = getResultAsPlain(representation);
|
CharSequence output = getResultAsPlain(representation);
|
||||||
if (output == null) {
|
|
||||||
output = String.valueOf(representation);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Pattern.compile(
|
return Pattern.compile(
|
||||||
matcher.group(1) + placeholder + matcher.group(3),
|
matcher.group(1) + placeholder + matcher.group(3),
|
||||||
Pattern.LITERAL
|
Pattern.LITERAL
|
||||||
@ -274,15 +271,27 @@ public class PlaceholderServiceImpl implements PlaceholderService {
|
|||||||
|
|
||||||
private static class ClassProviderLoader implements CacheLoader<Class<?>, Set<PlaceholderProvider>> {
|
private static class ClassProviderLoader implements CacheLoader<Class<?>, Set<PlaceholderProvider>> {
|
||||||
|
|
||||||
|
private Set<Class<?>> getAll(Class<?> clazz) {
|
||||||
|
Set<Class<?>> classes = new LinkedHashSet<>();
|
||||||
|
classes.add(clazz);
|
||||||
|
|
||||||
|
for (Class<?> anInterface : clazz.getInterfaces()) {
|
||||||
|
classes.addAll(getAll(anInterface));
|
||||||
|
}
|
||||||
|
|
||||||
|
Class<?> superClass = clazz.getSuperclass();
|
||||||
|
if (superClass != null) {
|
||||||
|
classes.addAll(getAll(superClass));
|
||||||
|
}
|
||||||
|
|
||||||
|
return classes;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable Set<PlaceholderProvider> load(@NonNull Class<?> key) {
|
public @Nullable Set<PlaceholderProvider> load(@NonNull Class<?> key) {
|
||||||
Set<PlaceholderProvider> providers = new HashSet<>();
|
Set<PlaceholderProvider> providers = new HashSet<>();
|
||||||
|
|
||||||
Class<?> currentClass = key;
|
Set<Class<?>> classes = getAll(key);
|
||||||
do {
|
|
||||||
List<Class<?>> classes = new ArrayList<>(Arrays.asList(currentClass.getInterfaces()));
|
|
||||||
classes.add(currentClass);
|
|
||||||
|
|
||||||
for (Class<?> clazz : classes) {
|
for (Class<?> clazz : classes) {
|
||||||
for (Method method : clazz.getMethods()) {
|
for (Method method : clazz.getMethods()) {
|
||||||
Placeholder annotation = method.getAnnotation(Placeholder.class);
|
Placeholder annotation = method.getAnnotation(Placeholder.class);
|
||||||
@ -314,9 +323,6 @@ public class PlaceholderServiceImpl implements PlaceholderService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
currentClass = currentClass.getSuperclass();
|
|
||||||
} while (currentClass != null);
|
|
||||||
|
|
||||||
return providers;
|
return providers;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,7 @@ public interface IPlayer extends DiscordSRVPlayer, IOfflinePlayer, ICommandSende
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
@Placeholder("player_name")
|
||||||
String username();
|
String username();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -94,6 +94,7 @@ dependencyResolutionManagement {
|
|||||||
// Integrations
|
// Integrations
|
||||||
library('luckperms', 'net.luckperms', 'api').version('5.4')
|
library('luckperms', 'net.luckperms', 'api').version('5.4')
|
||||||
library('vaultapi', 'net.milkbowl.vault', 'VaultAPI').version('1.7')
|
library('vaultapi', 'net.milkbowl.vault', 'VaultAPI').version('1.7')
|
||||||
|
library('placeholderapi-bukkit', 'me.clip', 'placeholderapi').version('2.11.1')
|
||||||
|
|
||||||
// Logging
|
// Logging
|
||||||
library('slf4j-api', 'org.slf4j', 'slf4j-api').version('1.7.36')
|
library('slf4j-api', 'org.slf4j', 'slf4j-api').version('1.7.36')
|
||||||
|
Loading…
Reference in New Issue
Block a user