mirror of
https://github.com/DiscordSRV/Ascension.git
synced 2024-11-25 12:25:15 +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;
|
||||
}
|
||||
|
||||
public Optional<Object> getContext(Class<?> type) {
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> Optional<T> getContext(Class<T> type) {
|
||||
for (Object o : contexts) {
|
||||
if (type.isAssignableFrom(o.getClass())) {
|
||||
return Optional.of(o);
|
||||
return Optional.of((T) o);
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
|
@ -25,6 +25,7 @@ package com.discordsrv.api.placeholder;
|
||||
|
||||
import com.discordsrv.api.placeholder.mapper.PlaceholderResultMapper;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
@ -52,6 +53,9 @@ public interface PlaceholderService {
|
||||
PlaceholderLookupResult lookupPlaceholder(@NotNull String placeholder, @NotNull Object... context);
|
||||
|
||||
Object getResult(@NotNull Matcher matcher, @NotNull Set<Object> context);
|
||||
@NotNull
|
||||
CharSequence getResultAsPlain(@NotNull Matcher matcher, @NotNull Set<Object> context);
|
||||
@NotNull
|
||||
CharSequence getResultAsPlain(@Nullable Object result);
|
||||
|
||||
}
|
||||
|
@ -23,7 +23,6 @@
|
||||
|
||||
package com.discordsrv.api.player;
|
||||
|
||||
import com.discordsrv.api.placeholder.annotation.Placeholder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.UUID;
|
||||
@ -37,7 +36,6 @@ public interface DiscordSRVPlayer {
|
||||
* The username of the player.
|
||||
* @return the player's username
|
||||
*/
|
||||
@Placeholder("player_name")
|
||||
@NotNull
|
||||
String username();
|
||||
|
||||
@ -45,7 +43,6 @@ public interface DiscordSRVPlayer {
|
||||
* The {@link UUID} of the player.
|
||||
* @return the player's unique id
|
||||
*/
|
||||
@Placeholder("player_uuid")
|
||||
@NotNull
|
||||
UUID uniqueId();
|
||||
|
||||
|
@ -44,6 +44,7 @@ allprojects {
|
||||
}
|
||||
filter {
|
||||
includeGroup 'net.milkbowl.vault'
|
||||
includeGroup 'me.clip'
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -79,6 +80,7 @@ dependencies {
|
||||
|
||||
// Integrations
|
||||
compileOnly(libs.vaultapi)
|
||||
compileOnly(libs.placeholderapi.bukkit)
|
||||
}
|
||||
|
||||
processResources {
|
||||
|
@ -225,6 +225,7 @@ public class BukkitDiscordSRV extends ServerDiscordSRV<DiscordSRVBukkitBootstrap
|
||||
|
||||
// Integrations
|
||||
registerIntegration("com.discordsrv.bukkit.integration.VaultIntegration");
|
||||
registerIntegration("com.discordsrv.bukkit.integration.PlaceholderAPIIntegration");
|
||||
|
||||
super.enable();
|
||||
|
||||
|
@ -37,6 +37,7 @@ public class DiscordSRVBukkitBootstrap extends BukkitBootstrap implements IBoots
|
||||
private final Logger logger;
|
||||
private final LifecycleManager lifecycleManager;
|
||||
private BukkitDiscordSRV discordSRV;
|
||||
private final List<Runnable> mainThreadTasksForDisable = new ArrayList<>();
|
||||
|
||||
public DiscordSRVBukkitBootstrap(JarInJarClassLoader classLoader, JavaPlugin plugin) throws IOException {
|
||||
// Don't change these parameters
|
||||
@ -73,6 +74,11 @@ public class DiscordSRVBukkitBootstrap extends BukkitBootstrap implements IBoots
|
||||
@Override
|
||||
public void onDisable() {
|
||||
lifecycleManager.disable(discordSRV);
|
||||
|
||||
// Run tasks on the main thread (scheduler cannot be used when disabling)
|
||||
for (Runnable runnable : mainThreadTasksForDisable) {
|
||||
runnable.run();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -94,4 +100,8 @@ public class DiscordSRVBukkitBootstrap extends BukkitBootstrap implements IBoots
|
||||
public Path dataDirectory() {
|
||||
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;
|
||||
|
||||
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.server.scheduler.ServerScheduler;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
public class BukkitScheduler extends StandardScheduler implements ServerScheduler {
|
||||
|
||||
@ -31,18 +36,28 @@ public class BukkitScheduler extends StandardScheduler implements ServerSchedule
|
||||
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
|
||||
public void runOnMainThread(Runnable task) {
|
||||
discordSRV.server().getScheduler().runTask(discordSRV.plugin(), task);
|
||||
checkDisable(task, (scheduler, plugin) -> scheduler.runTask(plugin, task));
|
||||
}
|
||||
|
||||
@Override
|
||||
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
|
||||
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
|
||||
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);
|
||||
return getResultAsPlain(result);
|
||||
}
|
||||
|
||||
private CharSequence getResultAsPlain(Object result) {
|
||||
@Override
|
||||
public @NotNull CharSequence getResultAsPlain(@Nullable Object result) {
|
||||
if (result == null) {
|
||||
return "";
|
||||
} else if (result instanceof CharSequence) {
|
||||
@ -214,10 +215,6 @@ public class PlaceholderServiceImpl implements PlaceholderService {
|
||||
Object representation = getResultRepresentation(results, placeholder, matcher);
|
||||
|
||||
CharSequence output = getResultAsPlain(representation);
|
||||
if (output == null) {
|
||||
output = String.valueOf(representation);
|
||||
}
|
||||
|
||||
return Pattern.compile(
|
||||
matcher.group(1) + placeholder + matcher.group(3),
|
||||
Pattern.LITERAL
|
||||
@ -274,15 +271,27 @@ public class PlaceholderServiceImpl implements PlaceholderService {
|
||||
|
||||
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
|
||||
public @Nullable Set<PlaceholderProvider> load(@NonNull Class<?> key) {
|
||||
Set<PlaceholderProvider> providers = new HashSet<>();
|
||||
|
||||
Class<?> currentClass = key;
|
||||
do {
|
||||
List<Class<?>> classes = new ArrayList<>(Arrays.asList(currentClass.getInterfaces()));
|
||||
classes.add(currentClass);
|
||||
|
||||
Set<Class<?>> classes = getAll(key);
|
||||
for (Class<?> clazz : classes) {
|
||||
for (Method method : clazz.getMethods()) {
|
||||
Placeholder annotation = method.getAnnotation(Placeholder.class);
|
||||
@ -314,9 +323,6 @@ public class PlaceholderServiceImpl implements PlaceholderService {
|
||||
}
|
||||
}
|
||||
|
||||
currentClass = currentClass.getSuperclass();
|
||||
} while (currentClass != null);
|
||||
|
||||
return providers;
|
||||
}
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ public interface IPlayer extends DiscordSRVPlayer, IOfflinePlayer, ICommandSende
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Placeholder("player_name")
|
||||
String username();
|
||||
|
||||
@Override
|
||||
|
@ -94,6 +94,7 @@ dependencyResolutionManagement {
|
||||
// Integrations
|
||||
library('luckperms', 'net.luckperms', 'api').version('5.4')
|
||||
library('vaultapi', 'net.milkbowl.vault', 'VaultAPI').version('1.7')
|
||||
library('placeholderapi-bukkit', 'me.clip', 'placeholderapi').version('2.11.1')
|
||||
|
||||
// Logging
|
||||
library('slf4j-api', 'org.slf4j', 'slf4j-api').version('1.7.36')
|
||||
|
Loading…
Reference in New Issue
Block a user