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