forked from Upstream/Velocitab
Add support for PlaceholderAPI placeholders via PAPIProxyBridge (#17)
* Start PAPI hook work * Finish adding PlaceholderAPI support
This commit is contained in:
parent
7d85ed6cfe
commit
f790378182
1
.github/workflows/java_ci.yml
vendored
1
.github/workflows/java_ci.yml
vendored
@ -45,6 +45,7 @@ jobs:
|
||||
dependencies: |
|
||||
protocolize | depends | 2.2.5
|
||||
luckperms | suggests | *
|
||||
papiproxybridge | suggests | *
|
||||
game-versions: |
|
||||
1.19
|
||||
1.19.2
|
||||
|
@ -10,7 +10,7 @@ version = "1.0.1-${versionMetadata()}"
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven { url = 'https://repo.papermc.io/repository/maven-public/' }
|
||||
maven { url = 'https://jitpack.io' }
|
||||
maven { url = 'https://jitpack.io/' }
|
||||
maven { url = 'https://repo.minebench.de/' }
|
||||
maven { url = 'https://mvn.exceptionflug.de/repository/exceptionflug-public/' }
|
||||
}
|
||||
@ -20,6 +20,7 @@ dependencies {
|
||||
compileOnly 'net.luckperms:api:5.4'
|
||||
compileOnly 'dev.simplix:protocolize-api:2.2.5'
|
||||
compileOnly 'io.netty:netty-codec-http:4.1.89.Final'
|
||||
compileOnly 'net.william278:PAPIProxyBridge:1.0'
|
||||
|
||||
implementation 'org.apache.commons:commons-text:1.10.0'
|
||||
implementation 'net.william278:Annotaml:2.0.1'
|
||||
|
@ -10,7 +10,8 @@ import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
import net.william278.annotaml.Annotaml;
|
||||
import net.william278.velocitab.config.Settings;
|
||||
import net.william278.velocitab.luckperms.LuckPermsHook;
|
||||
import net.william278.velocitab.hook.LuckPermsHook;
|
||||
import net.william278.velocitab.hook.PapiHook;
|
||||
import net.william278.velocitab.packet.ScoreboardManager;
|
||||
import net.william278.velocitab.player.Role;
|
||||
import net.william278.velocitab.player.TabPlayer;
|
||||
@ -34,7 +35,8 @@ import java.util.Optional;
|
||||
authors = {"William278"},
|
||||
dependencies = {
|
||||
@Dependency(id = "protocolize"),
|
||||
@Dependency(id = "luckperms", optional = true)
|
||||
@Dependency(id = "luckperms", optional = true),
|
||||
@Dependency(id = "papiproxybridge", optional = true)
|
||||
}
|
||||
)
|
||||
public class Velocitab {
|
||||
@ -45,6 +47,7 @@ public class Velocitab {
|
||||
private final Path dataDirectory;
|
||||
private PlayerTabList tabList;
|
||||
private LuckPermsHook luckPerms;
|
||||
private PapiHook papiHook;
|
||||
private ScoreboardManager scoreboardManager;
|
||||
|
||||
@Inject
|
||||
@ -85,17 +88,29 @@ public class Velocitab {
|
||||
return Optional.ofNullable(luckPerms);
|
||||
}
|
||||
|
||||
public Optional<PapiHook> getPapiHook() {
|
||||
return Optional.ofNullable(papiHook);
|
||||
}
|
||||
|
||||
private void loadHooks() {
|
||||
if (server.getPluginManager().getPlugin("luckperms").isEmpty()) {
|
||||
return;
|
||||
// If LuckPerms is present, load the hook
|
||||
if (server.getPluginManager().getPlugin("luckperms").isPresent()) {
|
||||
try {
|
||||
luckPerms = new LuckPermsHook(this);
|
||||
logger.info("Successfully hooked into LuckPerms");
|
||||
} catch (IllegalArgumentException e) {
|
||||
logger.warn("LuckPerms was not loaded: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
// If LuckPerms is present, load the hook
|
||||
try {
|
||||
luckPerms = new LuckPermsHook(this);
|
||||
logger.info("Successfully hooked into LuckPerms");
|
||||
} catch (IllegalArgumentException e) {
|
||||
logger.warn("LuckPerms was not loaded: " + e.getMessage(), e);
|
||||
// If PAPIProxyBridge is present, load the hook
|
||||
if (settings.isPapiHookEnabled() && server.getPluginManager().getPlugin("papiproxybridge").isPresent()) {
|
||||
try {
|
||||
papiHook = new PapiHook();
|
||||
logger.info("Successfully hooked into PAPIProxyBridge");
|
||||
} catch (IllegalArgumentException e) {
|
||||
logger.warn("PAPIProxyBridge was not loaded: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public enum Placeholder {
|
||||
@ -35,17 +36,20 @@ public enum Placeholder {
|
||||
this.formatter = formatter;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String format(@NotNull String format, @NotNull Velocitab plugin, @NotNull TabPlayer player) {
|
||||
public static CompletableFuture<String> format(@NotNull String format, @NotNull Velocitab plugin, @NotNull TabPlayer player) {
|
||||
for (Placeholder placeholder : values()) {
|
||||
format = format.replace("%" + placeholder.name().toLowerCase() + "%", placeholder.formatter.apply(plugin, player));
|
||||
}
|
||||
final String replaced = format;
|
||||
|
||||
return format;
|
||||
return plugin.getPapiHook()
|
||||
.map(hook -> hook.formatPapiPlaceholders(replaced, player.getPlayer()))
|
||||
.orElse(CompletableFuture.completedFuture(replaced));
|
||||
}
|
||||
|
||||
// Replace __ so that it is not seen as underline when the string is formatted.
|
||||
@NotNull
|
||||
private static String escape(String replace) {
|
||||
// Replace __ so that it is not seen as underline when the string is formatted.
|
||||
return replace.replace("__", "_\\_");
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.william278.velocitab.config;
|
||||
|
||||
import net.william278.annotaml.YamlComment;
|
||||
import net.william278.annotaml.YamlFile;
|
||||
import net.william278.annotaml.YamlKey;
|
||||
import net.william278.velocitab.BuildConstants;
|
||||
@ -22,6 +23,9 @@ public class Settings {
|
||||
private String footer = "[There are currently %players_online%/%max_players_online% players online](gray)";
|
||||
@YamlKey("format")
|
||||
private String format = "&7[%server%] &f%prefix%%username%";
|
||||
@YamlComment("Enable the PlaceholderAPI hook (requires PAPIProxyBridge to be installed on proxy & spigot servers)")
|
||||
@YamlKey("enable_papi_hook")
|
||||
private boolean enablePapiHook = true;
|
||||
@YamlKey("excluded_servers")
|
||||
private ArrayList<String> excludedServers = new ArrayList<>();
|
||||
@YamlKey(("update_rate"))
|
||||
@ -49,6 +53,10 @@ public class Settings {
|
||||
return excludedServers.contains(serverName);
|
||||
}
|
||||
|
||||
public boolean isPapiHookEnabled() {
|
||||
return enablePapiHook;
|
||||
}
|
||||
|
||||
public int getUpdateRate() {
|
||||
return updateRate;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package net.william278.velocitab.luckperms;
|
||||
package net.william278.velocitab.hook;
|
||||
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import net.luckperms.api.LuckPerms;
|
22
src/main/java/net/william278/velocitab/hook/PapiHook.java
Normal file
22
src/main/java/net/william278/velocitab/hook/PapiHook.java
Normal file
@ -0,0 +1,22 @@
|
||||
package net.william278.velocitab.hook;
|
||||
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import net.william278.papiproxybridge.api.PlaceholderAPI;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class PapiHook {
|
||||
|
||||
private final PlaceholderAPI api;
|
||||
|
||||
public PapiHook() {
|
||||
this.api = PlaceholderAPI.getInstance();
|
||||
}
|
||||
|
||||
public CompletableFuture<String> formatPapiPlaceholders(@NotNull String input, @NotNull Player player) {
|
||||
return api.formatPlaceholders(input, player.getUniqueId());
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -8,6 +8,8 @@ import net.william278.velocitab.config.Placeholder;
|
||||
import net.william278.velocitab.tab.PlayerTabList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public final class TabPlayer implements Comparable<TabPlayer> {
|
||||
private final Player player;
|
||||
private final Role role;
|
||||
@ -37,8 +39,9 @@ public final class TabPlayer implements Comparable<TabPlayer> {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Component getDisplayName(@NotNull Velocitab plugin) {
|
||||
return new MineDown(Placeholder.format(plugin.getSettings().getFormat(), plugin, this)).toComponent();
|
||||
public CompletableFuture<Component> getDisplayName(@NotNull Velocitab plugin) {
|
||||
return Placeholder.format(plugin.getSettings().getFormat(), plugin, this)
|
||||
.thenApply(formatted -> new MineDown(formatted).toComponent());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@ -47,7 +50,8 @@ public final class TabPlayer implements Comparable<TabPlayer> {
|
||||
}
|
||||
|
||||
public void sendHeaderAndFooter(@NotNull PlayerTabList tabList) {
|
||||
this.player.sendPlayerListHeaderAndFooter(tabList.getHeader(this), tabList.getFooter(this));
|
||||
tabList.getHeader(this).thenAccept(header -> tabList.getFooter(this)
|
||||
.thenAccept(footer -> player.sendPlayerListHeaderAndFooter(header, footer)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -17,6 +17,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@ -67,8 +68,8 @@ public class PlayerTabList {
|
||||
tabList.getEntries().stream()
|
||||
.filter(e -> e.getProfile().getId().equals(player.getPlayer().getUniqueId())).findFirst()
|
||||
.ifPresentOrElse(
|
||||
entry -> entry.setDisplayName(player.getDisplayName(plugin)),
|
||||
() -> tabList.addEntry(createEntry(player, tabList))
|
||||
entry -> player.getDisplayName(plugin).thenAccept(entry::setDisplayName),
|
||||
() -> createEntry(player, tabList).thenAccept(tabList::addEntry)
|
||||
);
|
||||
addPlayerToTabList(player, tabPlayer);
|
||||
player.sendHeaderAndFooter(this);
|
||||
@ -80,13 +81,13 @@ public class PlayerTabList {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private TabListEntry createEntry(@NotNull TabPlayer player, @NotNull TabList tabList) {
|
||||
return TabListEntry.builder()
|
||||
private CompletableFuture<TabListEntry> createEntry(@NotNull TabPlayer player, @NotNull TabList tabList) {
|
||||
return player.getDisplayName(plugin).thenApply(name -> TabListEntry.builder()
|
||||
.profile(player.getPlayer().getGameProfile())
|
||||
.displayName(player.getDisplayName(plugin))
|
||||
.displayName(name)
|
||||
.latency(0)
|
||||
.tabList(tabList)
|
||||
.build();
|
||||
.build());
|
||||
}
|
||||
|
||||
private void addPlayerToTabList(@NotNull TabPlayer player, @NotNull TabPlayer newPlayer) {
|
||||
@ -98,9 +99,9 @@ public class PlayerTabList {
|
||||
.getTabList().getEntries().stream()
|
||||
.filter(e -> e.getProfile().getId().equals(newPlayer.getPlayer().getUniqueId())).findFirst()
|
||||
.ifPresentOrElse(
|
||||
entry -> entry.setDisplayName(newPlayer.getDisplayName(plugin)),
|
||||
() -> player.getPlayer().getTabList()
|
||||
.addEntry(createEntry(newPlayer, player.getPlayer().getTabList()))
|
||||
entry -> newPlayer.getDisplayName(plugin).thenAccept(entry::setDisplayName),
|
||||
() -> createEntry(newPlayer, player.getPlayer().getTabList())
|
||||
.thenAccept(entry -> player.getPlayer().getTabList().addEntry(entry))
|
||||
);
|
||||
plugin.getScoreboardManager().updateRoles(
|
||||
player.getPlayer(),
|
||||
@ -129,25 +130,26 @@ public class PlayerTabList {
|
||||
|
||||
public void onUpdate(@NotNull TabPlayer tabPlayer) {
|
||||
plugin.getServer().getScheduler()
|
||||
.buildTask(plugin, () -> players.forEach(player -> {
|
||||
.buildTask(plugin, () -> players.forEach(player -> tabPlayer.getDisplayName(plugin).thenAccept(displayName -> {
|
||||
player.getPlayer().getTabList().getEntries().stream()
|
||||
.filter(e -> e.getProfile().getId().equals(tabPlayer.getPlayer().getUniqueId())).findFirst()
|
||||
.ifPresent(entry -> entry.setDisplayName(tabPlayer.getDisplayName(plugin)));
|
||||
.ifPresent(entry -> entry.setDisplayName(displayName));
|
||||
plugin.getScoreboardManager().updateRoles(player.getPlayer(),
|
||||
tabPlayer.getTeamName(), tabPlayer.getPlayer().getUsername());
|
||||
}))
|
||||
})))
|
||||
.delay(500, TimeUnit.MILLISECONDS)
|
||||
.schedule();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Component getHeader(@NotNull TabPlayer player) {
|
||||
return new MineDown(Placeholder.format(plugin.getSettings().getHeader(), plugin, player)).toComponent();
|
||||
public CompletableFuture<Component> getHeader(@NotNull TabPlayer player) {
|
||||
return Placeholder.format(plugin.getSettings().getHeader(), plugin, player)
|
||||
.thenApply(header -> new MineDown(header).toComponent());
|
||||
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Component getFooter(@NotNull TabPlayer player) {
|
||||
return new MineDown(Placeholder.format(plugin.getSettings().getFooter(), plugin, player)).toComponent();
|
||||
public CompletableFuture<Component> getFooter(@NotNull TabPlayer player) {
|
||||
return Placeholder.format(plugin.getSettings().getFooter(), plugin, player)
|
||||
.thenApply(header -> new MineDown(header).toComponent());
|
||||
}
|
||||
|
||||
private void updateTimer(int updateRate) {
|
||||
|
Loading…
Reference in New Issue
Block a user