Add optional support for MiniMessage and hook for MiniPlaceholders (#18)

This commit is contained in:
William 2023-03-11 20:23:47 +00:00 committed by GitHub
parent cb011c4e66
commit b431ee2165
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 168 additions and 43 deletions

View File

@ -46,6 +46,7 @@ jobs:
protocolize | depends | 2.2.5
luckperms | suggests | *
papiproxybridge | suggests | *
miniplaceholders | suggests | *
game-versions: |
1.16.5
1.17.1

View File

@ -26,8 +26,10 @@ 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 'io.github.miniplaceholders:miniplaceholders-api:2.0.0'
compileOnly 'net.william278:PAPIProxyBridge:1.0'
compileOnly 'org.projectlombok:lombok:1.18.26'
compileOnly 'net.kyori:adventure-text-minimessage:4.12.0'
implementation 'org.apache.commons:commons-text:1.10.0'
implementation 'net.william278:Annotaml:2.0.1'

View File

@ -3,5 +3,5 @@ javaVersion=16
org.gradle.jvmargs='-Dfile.encoding=UTF-8'
org.gradle.daemon=true
plugin_version=1.1.1
plugin_version=1.2
plugin_archive=velocitab

View File

@ -7,9 +7,14 @@ import com.velocitypowered.api.plugin.Plugin;
import com.velocitypowered.api.plugin.annotation.DataDirectory;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ProxyServer;
import de.themoep.minedown.adventure.MineDown;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.william278.annotaml.Annotaml;
import net.william278.velocitab.config.Settings;
import net.william278.velocitab.hook.Hook;
import net.william278.velocitab.hook.LuckPermsHook;
import net.william278.velocitab.hook.MiniPlaceholdersHook;
import net.william278.velocitab.hook.PapiHook;
import net.william278.velocitab.packet.ScoreboardManager;
import net.william278.velocitab.player.Role;
@ -22,12 +27,12 @@ import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
@Plugin(
id = "velocitab"
)
@Plugin(id = "velocitab")
public class Velocitab {
private Settings settings;
@ -35,8 +40,7 @@ public class Velocitab {
private final Logger logger;
private final Path dataDirectory;
private PlayerTabList tabList;
private LuckPermsHook luckPerms;
private PapiHook papiHook;
private List<Hook> hooks;
private ScoreboardManager scoreboardManager;
@Inject
@ -76,34 +80,38 @@ public class Velocitab {
}
}
private <H extends Hook> Optional<H> getHook(@NotNull Class<H> hookType) {
return hooks.stream()
.filter(hook -> hook.getClass().equals(hookType))
.map(hookType::cast)
.findFirst();
}
public Optional<LuckPermsHook> getLuckPerms() {
return Optional.ofNullable(luckPerms);
return getHook(LuckPermsHook.class);
}
public Optional<PapiHook> getPapiHook() {
return Optional.ofNullable(papiHook);
return getHook(PapiHook.class);
}
public Optional<MiniPlaceholdersHook> getMiniPlaceholdersHook() {
return getHook(MiniPlaceholdersHook.class);
}
private void loadHooks() {
// 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);
}
}
this.hooks = new ArrayList<>();
Hook.AVAILABLE.forEach(availableHook -> availableHook.apply(this).ifPresent(hooks::add));
}
// 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);
}
}
@NotNull
public Component formatText(@NotNull String text, @NotNull TabPlayer player) {
return switch (getSettings().getFormatter()) {
case MINEDOWN -> new MineDown(text).toComponent();
case MINIMESSAGE -> getMiniPlaceholdersHook()
.map(hook -> hook.format(text, player.getPlayer()))
.orElse(MiniMessage.miniMessage().deserialize(text));
};
}
private void prepareScoreboardManager() {

View File

@ -20,27 +20,42 @@ import java.util.Map;
Placeholders: %players_online%, %max_players_online%, %local_players_online%, %current_date%, %current_time%, %username%, %server%, %ping%, %prefix%, %suffix%, %role%""")
public class Settings {
@YamlKey("headers")
private Map<String, String> headers = Map.of("default", "&rainbow&Running Velocitab by William278");
@YamlKey("footers")
private Map<String, String> footers = Map.of("default", "[There are currently %players_online%/%max_players_online% players online](gray)");
@YamlKey("formats")
private Map<String, String> formats = Map.of("default", "&7[%server%] &f%prefix%%username%");
@Getter
@YamlComment("Which text formatter to use (MINEDOWN or MINIMESSAGE)")
@YamlKey("formatting_type")
private Formatter formatter = Formatter.MINEDOWN;
@Getter
@YamlKey("server_groups")
@YamlComment("The servers in each group of servers")
private Map<String, List<String>> serverGroups = Map.of("default", List.of("lobby1", "lobby2", "lobby3"));
@Getter
@YamlKey("fallback_enabled")
@YamlComment("All servers which are not in other groups will be put in the fallback group.\n\"false\" will exclude them from Velocitab.")
private boolean fallbackEnabled = true;
@Getter
@YamlKey("fallback_group")
@YamlComment("The formats to use for the fallback group.")
private String fallbackGroup = "default";
@YamlKey("enable_papi_hook")
private boolean enablePapiHook = true;
@YamlKey("enable_miniplaceholders_hook")
@YamlComment("If you are using MINIMESSAGE formatting, enable this to support MiniPlaceholders in formatting.")
private boolean enableMiniPlaceholdersHook = true;
@YamlKey("update_rate")
@YamlComment("How often to periodically update the TAB list, including header and footer, for all users.\nWill only update on player join/leave if set to 0.")
private int updateRate = 0;
@ -50,8 +65,10 @@ public class Settings {
plugin.getServer().getAllServers().stream().map(server -> server.getServerInfo().getName()).toList()
);
}
@SuppressWarnings("unused")
public Settings(){}
public Settings() {
}
@NotNull
public String getHeader(String serverGroup) {
@ -87,7 +104,19 @@ public class Settings {
return enablePapiHook;
}
public boolean isMiniPlaceholdersHookEnabled() {
return enableMiniPlaceholdersHook;
}
public int getUpdateRate() {
return updateRate;
}
/**
* Different formatting markup options for the TAB list
*/
public enum Formatter {
MINEDOWN,
MINIMESSAGE
}
}

View File

@ -0,0 +1,58 @@
package net.william278.velocitab.hook;
import net.william278.velocitab.Velocitab;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
public abstract class Hook {
public static final List<Function<Velocitab, Optional<Hook>>> AVAILABLE = List.of(
(plugin -> {
if (isPluginAvailable(plugin, "luckperms")) {
try {
plugin.log("Successfully hooked into LuckPerms");
return Optional.of(new LuckPermsHook(plugin));
} catch (Exception e) {
plugin.log("LuckPerms hook was not loaded: " + e.getMessage(), e);
}
}
return Optional.empty();
}),
(plugin -> {
if (isPluginAvailable(plugin, "papiproxybridge") && plugin.getSettings().isPapiHookEnabled()) {
try {
plugin.log("Successfully hooked into PAPIProxyBridge");
return Optional.of(new PapiHook(plugin));
} catch (Exception e) {
plugin.log("PAPIProxyBridge hook was not loaded: " + e.getMessage(), e);
}
}
return Optional.empty();
}),
(plugin -> {
if (isPluginAvailable(plugin, "miniplaceholders") && plugin.getSettings().isMiniPlaceholdersHookEnabled()) {
try {
plugin.log("Successfully hooked into MiniPlaceholders");
return Optional.of(new MiniPlaceholdersHook(plugin));
} catch (Exception e) {
plugin.log("MiniPlaceholders hook was not loaded: " + e.getMessage(), e);
}
}
return Optional.empty();
})
);
protected final Velocitab plugin;
public Hook(@NotNull Velocitab plugin) {
this.plugin = plugin;
}
private static boolean isPluginAvailable(@NotNull Velocitab plugin, @NotNull String id) {
return plugin.getServer().getPluginManager().getPlugin(id).isPresent();
}
}

View File

@ -16,14 +16,13 @@ import org.jetbrains.annotations.Nullable;
import java.util.OptionalInt;
import java.util.UUID;
public class LuckPermsHook {
public class LuckPermsHook extends Hook {
private int highestWeight = Role.DEFAULT_WEIGHT;
private final Velocitab plugin;
private final LuckPerms api;
public LuckPermsHook(@NotNull Velocitab plugin) throws IllegalStateException {
this.plugin = plugin;
super(plugin);
this.api = LuckPermsProvider.get();
api.getEventBus().subscribe(plugin, UserDataRecalculateEvent.class, this::onLuckPermsGroupUpdate);
}

View File

@ -0,0 +1,21 @@
package net.william278.velocitab.hook;
import io.github.miniplaceholders.api.MiniPlaceholders;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.william278.velocitab.Velocitab;
import org.jetbrains.annotations.NotNull;
public class MiniPlaceholdersHook extends Hook {
public MiniPlaceholdersHook(@NotNull Velocitab plugin) {
super(plugin);
}
@NotNull
public Component format(@NotNull String text, @NotNull Audience player) {
return MiniMessage.miniMessage().deserialize(text, MiniPlaceholders.getAudienceGlobalPlaceholders(player));
}
}

View File

@ -2,15 +2,17 @@ package net.william278.velocitab.hook;
import com.velocitypowered.api.proxy.Player;
import net.william278.papiproxybridge.api.PlaceholderAPI;
import net.william278.velocitab.Velocitab;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.CompletableFuture;
public class PapiHook {
public class PapiHook extends Hook {
private final PlaceholderAPI api;
public PapiHook() {
public PapiHook(@NotNull Velocitab plugin) {
super(plugin);
this.api = PlaceholderAPI.getInstance();
}

View File

@ -53,7 +53,11 @@ public class ScoreboardManager {
}
private void dispatchPacket(@NotNull UpdateTeamsPacket packet, @NotNull Player player) {
Protocolize.playerProvider().player(player.getUniqueId()).sendPacket(packet);
try {
Protocolize.playerProvider().player(player.getUniqueId()).sendPacket(packet);
} catch (Exception e) {
plugin.log("Failed to dispatch packet (is the client or server modded or using an illegal version?)", e);
}
}
public void registerPacket() {

View File

@ -1,7 +1,6 @@
package net.william278.velocitab.player;
import com.velocitypowered.api.proxy.Player;
import de.themoep.minedown.adventure.MineDown;
import net.kyori.adventure.text.Component;
import net.william278.velocitab.Velocitab;
import net.william278.velocitab.config.Placeholder;
@ -40,10 +39,9 @@ public final class TabPlayer implements Comparable<TabPlayer> {
@NotNull
public CompletableFuture<Component> getDisplayName(@NotNull Velocitab plugin) {
return Placeholder.format(plugin.getSettings().getFormat(
plugin.getSettings().getServerGroup(getServerName())
), plugin, this)
.thenApply(formatted -> new MineDown(formatted).toComponent());
final String serverGroup = plugin.getSettings().getServerGroup(getServerName());
return Placeholder.format(plugin.getSettings().getFormat(serverGroup), plugin, this)
.thenApply(formatted -> plugin.formatText(formatted, this));
}

View File

@ -8,7 +8,6 @@ import com.velocitypowered.api.proxy.ServerConnection;
import com.velocitypowered.api.proxy.player.TabList;
import com.velocitypowered.api.proxy.player.TabListEntry;
import com.velocitypowered.api.proxy.server.ServerInfo;
import de.themoep.minedown.adventure.MineDown;
import net.kyori.adventure.text.Component;
import net.william278.velocitab.Velocitab;
import net.william278.velocitab.config.Placeholder;
@ -74,7 +73,7 @@ public class PlayerTabList {
final Map<String, String> playerRoles = new HashMap<>();
for (TabPlayer player : players) {
if (!serversInGroup.get().contains(player.getServerName())) {
if (serversInGroup.isPresent() && !serversInGroup.get().contains(player.getServerName())) {
continue; // Skip players on other servers
}
playerRoles.put(player.getPlayer().getUsername(), player.getTeamName());
@ -158,14 +157,14 @@ public class PlayerTabList {
public CompletableFuture<Component> getHeader(@NotNull TabPlayer player) {
return Placeholder.format(plugin.getSettings().getHeader(
plugin.getSettings().getServerGroup(player.getServerName())), plugin, player)
.thenApply(header -> new MineDown(header).toComponent());
.thenApply(header -> plugin.formatText(header, player));
}
public CompletableFuture<Component> getFooter(@NotNull TabPlayer player) {
return Placeholder.format(plugin.getSettings().getFooter(
plugin.getSettings().getServerGroup(player.getServerName())), plugin, player)
.thenApply(header -> new MineDown(header).toComponent());
.thenApply(footer -> plugin.formatText(footer, player));
}

View File

@ -19,6 +19,10 @@
{
"id": "papiproxybridge",
"optional": true
},
{
"id": "miniplaceholders",
"optional": true
}
],
"main": "net.william278.velocitab.Velocitab"