Compare commits

...
23 changed files with 538 additions and 185 deletions

No files matched your search

+65
View File
@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>parent</artifactId>
<groupId>ch.andre601.advancedserverlist</groupId>
<version>parent</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>asl-placeholderapi</artifactId>
<packaging>jar</packaging>
<version>${plugin.version}</version>
<properties>
<maven.compiler.source>16</maven.compiler.source>
<maven.compuler.target>16</maven.compuler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<repositories>
<repository>
<id>papermc-repo</id>
<url>https://repo.papermc.io/repository/maven-public/</url>
</repository>
<repository>
<id>placeholderapi-repo</id>
<url>https://repo.extendedclip.com/content/repositories/placeholderapi/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>io.papermc.paper</groupId>
<artifactId>paper-api</artifactId>
<version>1.21-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>me.clip</groupId>
<artifactId>placeholderapi</artifactId>
<version>2.11.6</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>AdvancedServerList-PlaceholderAPI-Addon-${plugin.version}</finalName>
<resources>
<resource>
<filtering>true</filtering>
<directory>src/main/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,70 @@
package ch.andre601.placeholderapi;
import ch.andre601.placeholderapi.messenger.ASLPluginMessageListener;
import ch.andre601.placeholderapi.messenger.BungeeCordMessageListener;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.concurrent.Callable;
import java.util.logging.Level;
public final class ASLPlaceholderAPI extends JavaPlugin{
private String serverName = null;
@Override
public void onEnable(){
// Own Plugin Channel
getServer().getMessenger().registerOutgoingPluginChannel(this, pluginChannel());
getServer().getMessenger().registerIncomingPluginChannel(this, pluginChannel(), new ASLPluginMessageListener(this));
// BungeeCord Plugin Channel
getServer().getMessenger().registerOutgoingPluginChannel(this, "BungeeCord");
getServer().getMessenger().registerIncomingPluginChannel(this, "BungeeCord", new BungeeCordMessageListener(this));
requestServerName();
}
@Override
public void onDisable(){
getServer().getMessenger().unregisterOutgoingPluginChannel(this);
getServer().getMessenger().unregisterIncomingPluginChannel(this);
}
public void serverName(String serverName){
this.serverName = serverName;
}
public String pluginChannel(){
return "advancedserverlist:action";
}
public String serverName(){
return serverName;
}
public void waitUntil(Callable<Boolean> condition, Runnable action){
Bukkit.getScheduler().runTaskTimer(this, (task) -> {
try{
if(condition.call()){
action.run();
task.cancel();
}
}catch(Exception ex){
getLogger().log(Level.WARNING, "Encountered Exception while waiting for a task to finish.", ex);
}
}, 0L, 1L);
}
private void requestServerName(){
waitUntil(() -> !getServer().getOnlinePlayers().isEmpty(), () -> {
Player plmSender = Bukkit.getOnlinePlayers().iterator().next();
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("GetServer");
plmSender.sendPluginMessage(this, "BungeeCord", out.toByteArray());
});
}
}
@@ -0,0 +1,78 @@
package ch.andre601.placeholderapi.messenger;
import ch.andre601.placeholderapi.ASLPlaceholderAPI;
import me.clip.placeholderapi.PlaceholderAPI;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.bukkit.plugin.messaging.PluginMessageListener;
import org.jetbrains.annotations.NotNull;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.util.UUID;
import java.util.logging.Level;
public class ASLPluginMessageListener implements PluginMessageListener{
private final ASLPlaceholderAPI plugin;
public ASLPluginMessageListener(ASLPlaceholderAPI plugin){
this.plugin = plugin;
}
@Override
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, byte[] message){
if(!channel.equals(plugin.pluginChannel()))
return;
if(plugin.serverName() == null)
return;
ByteArrayInputStream stream = new ByteArrayInputStream(message);
DataInputStream in = new DataInputStream(stream);
try{
String action = in.readUTF();
switch(action){
case "findPlugins" -> sendPluginMessage("hasPlugin", plugin.serverName());
case "parsePlaceholder" -> {
UUID playerUuid = UUID.fromString(in.readUTF());
String text = in.readUTF();
if(!Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")){
sendPluginMessage("parsed", playerUuid.toString(), text);
return;
}
OfflinePlayer targetPlayer = Bukkit.getOfflinePlayer(playerUuid);
String parsed = PlaceholderAPI.setPlaceholders(targetPlayer, text);
sendPluginMessage("parsed", playerUuid.toString(), parsed);
}
default -> plugin.getLogger().warning("Received unknown plugin Message sub channel: " + action);
}
}catch(Exception ex){
plugin.getLogger().log(Level.WARNING, "Encountered an Exception while handling a plugin message.", ex);
}
}
private void sendPluginMessage(String channel, String... values){
plugin.waitUntil(
() -> !Bukkit.getOnlinePlayers().isEmpty() && plugin.serverName() != null,
() -> {
Player plmSender = Bukkit.getOnlinePlayers().iterator().next();
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
DataOutputStream dataOut = new DataOutputStream(outStream);
try{
dataOut.writeUTF(channel);
for(String value : values){
dataOut.writeUTF(value);
}
}catch(Exception ex){
plugin.getLogger().log(Level.WARNING, "Encountered an Exception while writiing data for plugin message.", ex);
}
plmSender.sendPluginMessage(plugin, plugin.pluginChannel(), outStream.toByteArray());
}
);
}
}
@@ -0,0 +1,34 @@
package ch.andre601.placeholderapi.messenger;
import ch.andre601.placeholderapi.ASLPlaceholderAPI;
import org.bukkit.entity.Player;
import org.bukkit.plugin.messaging.PluginMessageListener;
import org.jetbrains.annotations.NotNull;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.util.logging.Level;
public class BungeeCordMessageListener implements PluginMessageListener{
private final ASLPlaceholderAPI plugin;
public BungeeCordMessageListener(ASLPlaceholderAPI plugin){
this.plugin = plugin;
}
@Override
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, byte[] message){
if(!channel.equals("BungeeCord"))
return;
DataInputStream stream = new DataInputStream(new ByteArrayInputStream(message));
try{
String subChannel = stream.readUTF();
if("GetServer".equals(subChannel))
plugin.serverName(stream.readUTF());
}catch(Exception ex){
plugin.getLogger().log(Level.WARNING, "Encountered Exception while reading plugin message from Bungeecord channel.", ex);
}
}
}
@@ -0,0 +1,10 @@
name: ASL-PlaceholderAPI
version: '${plugin.version}'
main: ch.andre601.placeholderapi.ASLPlaceholderAPI
api-version: '1.21'
dependencies:
server:
PlaceholderAPI:
load: BEFORE
authors: [ Andre601 ]
description: Addon to allow PlaceholderAPI placeholders on your Velocity/BungeeCord proxy.
@@ -26,8 +26,9 @@
package ch.andre601.advancedserverlist.bungeecord;
import ch.andre601.advancedserverlist.bungeecord.commands.CmdAdvancedServerList;
import ch.andre601.advancedserverlist.bungeecord.listeners.JoinEvent;
import ch.andre601.advancedserverlist.bungeecord.listeners.PingEvent;
import ch.andre601.advancedserverlist.bungeecord.listeners.JoinListener;
import ch.andre601.advancedserverlist.bungeecord.listeners.PingListener;
import ch.andre601.advancedserverlist.bungeecord.listeners.PluginMessageListener;
import ch.andre601.advancedserverlist.bungeecord.logging.BungeeLogger;
import ch.andre601.advancedserverlist.bungeecord.objects.placeholders.BungeePlayerPlaceholders;
import ch.andre601.advancedserverlist.bungeecord.objects.placeholders.BungeeProxyPlaceholders;
@@ -35,9 +36,12 @@ import ch.andre601.advancedserverlist.bungeecord.objects.placeholders.BungeeServ
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
import ch.andre601.advancedserverlist.core.objects.PluginMessageUtil;
import ch.andre601.advancedserverlist.core.profiles.handlers.FaviconHandler;
import com.alessiodp.libby.BungeeLibraryManager;
import com.alessiodp.libby.Library;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import de.myzelyam.api.vanish.BungeeVanishAPI;
import net.kyori.adventure.platform.bungeecord.BungeeAudiences;
import net.md_5.bungee.api.Favicon;
@@ -60,6 +64,8 @@ import java.util.logging.Level;
public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
public static final String ASL_PLUGIN_CHANNEL = "advancedserverlist:action";
private final PluginLogger logger = new BungeeLogger(this);
private final Map<String, ServerPing> fetchedServers = new ConcurrentHashMap<>();
@@ -111,8 +117,9 @@ public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
@Override
public void loadEvents(){
new JoinEvent(this);
new PingEvent(this);
new JoinListener(this);
new PingListener(this);
new PluginMessageListener(this);
}
@Override
@@ -241,11 +248,17 @@ public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
private void fetchServers(){
fetchedServers.clear();
PluginMessageUtil.get().clear();
getProxy().getServers().forEach((name, server) -> server.ping((ping, throwable) -> {
if(throwable != null)
return;
fetchedServers.put(name, ping);
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("findPlugins");
server.sendData(ASL_PLUGIN_CHANNEL, out.toByteArray());
}));
}
}
@@ -32,19 +32,20 @@ import ch.andre601.advancedserverlist.bungeecord.BungeeCordCore;
import ch.andre601.advancedserverlist.bungeecord.objects.impl.BungeePlayerImpl;
import ch.andre601.advancedserverlist.bungeecord.objects.impl.BungeeProxyImpl;
import ch.andre601.advancedserverlist.core.compat.maintenance.MaintenanceUtil;
import ch.andre601.advancedserverlist.core.compat.papi.PAPIUtil;
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
import ch.andre601.advancedserverlist.core.interfaces.events.GenericEventWrapper;
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
import ch.andre601.advancedserverlist.core.objects.PluginMessageUtil;
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer;
import net.md_5.bungee.api.Favicon;
import net.md_5.bungee.api.ServerPing;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.ProxyPingEvent;
import java.net.InetSocketAddress;
@@ -174,25 +175,25 @@ public class BungeeEventWrapper implements GenericEventWrapper<Favicon, BungeePl
@Override
public String parsePAPIPlaceholders(String text, BungeePlayerImpl player){
if(plugin.getProxy().getPluginManager().getPlugin("PAPIProxyBridge") == null)
return text;
if(!PAPIUtil.get().isCompatible())
return text;
String server = PAPIUtil.get().getServer();
if(server == null || server.isEmpty())
return text;
ServerInfo serverInfo = plugin.getProxy().getServerInfo(server);
if(serverInfo == null || serverInfo.getPlayers().isEmpty())
return text;
ProxiedPlayer carrier = PAPIUtil.get().getPlayer(serverInfo.getPlayers());
if(carrier == null)
return text;
return PAPIUtil.get().parse(text, carrier.getUniqueId(), player.getUUID());
return PluginMessageUtil.get().getOrExecute(player.getUUID().toString(), text, (uuid, textValue) -> {
List<String> servers = PluginMessageUtil.get().getKnownServers();
if(servers.isEmpty())
return textValue;
ServerInfo serverInfo = plugin.getProxy().getServerInfo(servers.get(0));
if(serverInfo == null)
return textValue;
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("parse");
out.writeUTF(uuid);
out.writeUTF(textValue);
serverInfo.sendData(BungeeCordCore.ASL_PLUGIN_CHANNEL, out.toByteArray());
PluginMessageUtil.get().queue(uuid, textValue, false);
return PluginMessageUtil.get().getOrDefault(uuid, textValue);
});
}
@Override
@@ -34,10 +34,10 @@ import net.md_5.bungee.event.EventHandler;
import java.net.InetSocketAddress;
public class JoinEvent implements Listener{
public class JoinListener implements Listener{
private final BungeeCordCore plugin;
public JoinEvent(BungeeCordCore plugin){
public JoinListener(BungeeCordCore plugin){
this.plugin = plugin;
plugin.getProxy().getPluginManager().registerListener(plugin, this);
}
@@ -33,11 +33,11 @@ import net.md_5.bungee.api.event.ProxyPingEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler;
public class PingEvent implements Listener{
public class PingListener implements Listener{
private final BungeeCordCore plugin;
public PingEvent(BungeeCordCore plugin){
public PingListener(BungeeCordCore plugin){
this.plugin = plugin;
plugin.getProxy().getPluginManager().registerListener(plugin, this);
}
@@ -0,0 +1,37 @@
package ch.andre601.advancedserverlist.bungeecord.listeners;
import ch.andre601.advancedserverlist.bungeecord.BungeeCordCore;
import ch.andre601.advancedserverlist.core.objects.PluginMessageUtil;
import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteStreams;
import net.md_5.bungee.api.event.PluginMessageEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler;
public class PluginMessageListener implements Listener{
public PluginMessageListener(BungeeCordCore plugin){
plugin.getProxy().getPluginManager().registerListener(plugin, this);
}
@EventHandler
public void onPluginMessage(PluginMessageEvent event){
if(!event.getTag().equals(BungeeCordCore.ASL_PLUGIN_CHANNEL))
return;
ByteArrayDataInput input = ByteStreams.newDataInput(event.getData());
String subChannel = input.readUTF();
switch(subChannel){
case "hasPlugin" -> {
String serverName = input.readUTF();
PluginMessageUtil.get().addServer(serverName);
}
case "parsed" -> {
String uuid = input.readUTF();
String parsed = input.readUTF();
PluginMessageUtil.get().queue(uuid, parsed, true);
}
}
}
}
@@ -28,7 +28,7 @@ package ch.andre601.advancedserverlist.core.check;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
import ch.andre601.advancedserverlist.core.objects.ValueCache;
import ch.andre601.advancedserverlist.core.objects.CacheUtil;
import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@@ -59,7 +59,7 @@ public class UpdateChecker{
private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(new UpdateCheckThread());
private final ValueCache<CompletableFuture<ModrinthVersion>> cache = new ValueCache<>(Duration.ofMinutes(5));
private final CacheUtil.SingletonCache<CompletableFuture<ModrinthVersion>> cache = new CacheUtil.SingletonCache<>(Duration.ofMinutes(5));
private final AdvancedServerList<?> core;
private final PluginLogger logger;
@@ -441,7 +441,7 @@ public class CommandHandler{
.appendText("|")
.appendSpace()
// list
.appendLiteralArgument("list", "Lists all currently know profiles and wether they are valid or not.")
.appendLiteralArgument("list", "Lists all currently know profiles and whether they are valid or not.")
// Closing bracket
.appendText("></grey>")
.build();
@@ -32,7 +32,7 @@ public class CommandStringBuilder{
private final List<CommandPart> commandParts = new ArrayList<>();
public CommandStringBuilder(String subcommand, String description){
appendText("<hover:show_text:\"<grey>" + description + "</grey>\"><white>" + subcommand + "</white></hover>");
appendLiteralArgument(subcommand, description);
}
public CommandStringBuilder appendArgument(Argument argument){
@@ -1,92 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022-2023 Andre_601
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package ch.andre601.advancedserverlist.core.compat.papi;
import ch.andre601.advancedserverlist.core.objects.ValueCache;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import net.william278.papiproxybridge.api.PlaceholderAPI;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class PAPIUtil{
private static PAPIUtil instance;
private final ValueCache<CompletableFuture<Set<String>>> serversCache = new ValueCache<>(Duration.ofSeconds(10));
private final Cache<UUID, CompletableFuture<String>> textCache = CacheBuilder.newBuilder()
.expireAfterWrite(Duration.ofSeconds(10))
.build();
private final PlaceholderAPI papi;
private PAPIUtil(){
this.papi = PlaceholderAPI.createInstance();
}
public static PAPIUtil get(){
if(instance != null)
return instance;
return (instance = new PAPIUtil());
}
// Make sure the version of PAPIProxyBridge we get has the required methods we need...
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
public boolean isCompatible(){
try{
papi.getClass().getMethod("getServers");
return true;
}catch(NoSuchMethodException ex){
return false;
}
}
public String getServer(){
Set<String> values = serversCache.get(papi::getServers).getNow(Collections.emptySet());
if(values.isEmpty())
return null;
return List.copyOf(values).get(0);
}
public <P> P getPlayer(Collection<P> players){
if(players.isEmpty())
return null;
return List.copyOf(players).get(0);
}
public String parse(String text, UUID carrier, UUID player){
try{
return textCache.get(player, () -> papi.formatPlaceholders(text, carrier, player)).getNow(text);
}catch(ExecutionException ex){
return text;
}
}
}
@@ -26,25 +26,58 @@
package ch.andre601.advancedserverlist.core.objects;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
public class ValueCache<T>{
public abstract class CacheUtil{
private final Duration duration;
private CacheValue<T> cache = null;
protected final Duration duration;
public ValueCache(Duration duration){
public CacheUtil(Duration duration){
this.duration = duration;
}
public T get(Supplier<T> supplier){
if(cache == null || cache.expired())
cache = new CacheValue<>(System.currentTimeMillis(), duration, supplier.get());
public static class SingletonCache<T> extends CacheUtil{
return cache.value();
private CacheValue<T> cacheValue = null;
public SingletonCache(Duration duration){
super(duration);
}
public T get(Supplier<T> supplier){
if(cacheValue == null || cacheValue.expired())
cacheValue = new CacheValue<>(System.currentTimeMillis(), duration, supplier.get());
return cacheValue.value();
}
}
private record CacheValue<T>(long timestamp, Duration duration, T value){
public static class IdentifiableCache<K, V> extends CacheUtil{
private final Map<K, CacheValue<V>> cacheValues = new HashMap<>();
public IdentifiableCache(Duration duration){
super(duration);
}
public V get(K key, Supplier<V> supplier){
CacheValue<V> value = cacheValues.get(key);
if(value == null || value.expired()){
value = new CacheValue<>(System.currentTimeMillis(), duration, supplier.get());
cacheValues.put(key, value);
}
return cacheValues.get(key).value();
}
public void clear(){
cacheValues.clear();
}
}
public record CacheValue<T>(long timestamp, Duration duration, T value){
public boolean expired(){
return (timestamp < 0L) || System.currentTimeMillis() - timestamp >= duration.toMillis();
}
@@ -0,0 +1,57 @@
package ch.andre601.advancedserverlist.core.objects;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.BiFunction;
public class PluginMessageUtil{
private static PluginMessageUtil instance;
private final List<String> knownServers = new CopyOnWriteArrayList<>();
private final Map<String, ParsedText> text = new ConcurrentHashMap<>();
private PluginMessageUtil(){}
public static PluginMessageUtil get(){
if(instance != null)
return instance;
return (instance = new PluginMessageUtil());
}
public void addServer(String name){
this.knownServers.add(name);
}
public List<String> getKnownServers(){
return knownServers;
}
public void clear(){
knownServers.clear();
}
public String getOrExecute(String key, String value, BiFunction<String, String, String> function){
if(text.get(key) != null){
return getOrDefault(key, value);
}
return function.apply(key, value);
}
public void queue(String key, String value, boolean parsed){
text.put(key, new ParsedText(value, parsed));
}
public String getOrDefault(String key, String def){
if(text.get(key) == null)
return def;
return text.get(key).parsed() ? text.remove(key).text() : text.get(key).text();
}
private record ParsedText(String text, boolean parsed){}
}
@@ -27,8 +27,7 @@ package ch.andre601.advancedserverlist.core.profiles.handlers;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import ch.andre601.advancedserverlist.core.objects.CacheUtil;
import javax.imageio.ImageIO;
import java.awt.*;
@@ -42,9 +41,13 @@ import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.util.List;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
public class FaviconHandler<F>{
@@ -52,7 +55,7 @@ public class FaviconHandler<F>{
private final AdvancedServerList<F> core;
private final PluginLogger logger;
private final ThreadPoolExecutor faviconThreadPool;
private final Cache<String, CompletableFuture<F>> faviconCache;
private final CacheUtil.IdentifiableCache<String, CompletableFuture<F>> faviconCache;
private final Map<String, F> localFavicons = new HashMap<>();
private final HttpClient client = HttpClient.newHttpClient();
@@ -62,42 +65,32 @@ public class FaviconHandler<F>{
this.core = core;
this.logger = core.getPlugin().getPluginLogger();
this.faviconThreadPool = createFaviconThreadPool();
this.faviconCache = CacheBuilder.newBuilder()
.expireAfterWrite(core.getFileHandler().getLong(1, 1, "faviconCacheTime"), TimeUnit.MINUTES)
.build();
this.faviconCache = new CacheUtil.IdentifiableCache<>(Duration.ofMinutes(
core.getFileHandler().getLong(1, 1, "faviconCacheTime")
));
loadLocalFavicons();
}
public F getFavicon(String input){
if(localFavicons.size() > 0){
if(!localFavicons.isEmpty()){
logger.debug(FaviconHandler.class, "Current Local Favicons:");
for(String key : localFavicons.keySet()){
logger.debug(FaviconHandler.class, " - %s", key);
}
}
if(input.equalsIgnoreCase("random")){
logger.debug(FaviconHandler.class, "Input matches 'random'. Returning random Favicon...");
return getRandomized();
}
if(localFavicons.containsKey(input.toLowerCase(Locale.ROOT))){
logger.debug(FaviconHandler.class, "Input matches local favicon Image. Returning it...");
return localFavicons.get(input.toLowerCase(Locale.ROOT));
}
try{
logger.debug(FaviconHandler.class, "Getting Favicon image from cache...");
return faviconCache.get(input, () -> getFuture(input)).getNow(null);
}catch(ExecutionException ex){
logger.warn("Received ExecutionException while retrieving Favicon for '<white>%s</white>'.", ex, input);
return null;
}
logger.debug(FaviconHandler.class, "Getting Favicon image from cache...");
return faviconCache.get(input, () -> getFuture(input)).getNow(null);
}
public void cleanCache(){
faviconCache.invalidateAll();
faviconCache.clear();
loadLocalFavicons();
}
@@ -113,7 +106,7 @@ public class FaviconHandler<F>{
logger.debug(FaviconHandler.class, "Resolving image file '%s'...", input);
return CompletableFuture.completedFuture(localFavicons.get(input.toLowerCase(Locale.ROOT)));
}else{
logger.debug(FaviconHandler.class, "Resolving Name/UUID as https://mc-heads.net/avatar/%s/64...", input);
logger.debug(FaviconHandler.class, "Resolving '%s' as 'https://mc-heads.net/avatar/%s/64'...", input, input);
return CompletableFuture.supplyAsync(() -> fromURL(core, "https://mc-heads.net/avatar/" + input + "/64"), this.faviconThreadPool);
}
}
+1
View File
@@ -74,5 +74,6 @@
<module>velocity</module>
<module>version-uploader</module>
<module>addons/banplugins</module>
<module>addons/placeholderapi</module>
</modules>
</project>
@@ -30,14 +30,17 @@ import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
import ch.andre601.advancedserverlist.core.profiles.handlers.FaviconHandler;
import ch.andre601.advancedserverlist.velocity.commands.CmdAdvancedServerList;
import ch.andre601.advancedserverlist.velocity.listeners.JoinEvent;
import ch.andre601.advancedserverlist.velocity.listeners.PingEvent;
import ch.andre601.advancedserverlist.velocity.listeners.JoinListener;
import ch.andre601.advancedserverlist.velocity.listeners.PingListener;
import ch.andre601.advancedserverlist.velocity.listeners.PluginMessageListener;
import ch.andre601.advancedserverlist.velocity.logging.VelocityLogger;
import ch.andre601.advancedserverlist.velocity.objects.placeholders.VelocityPlayerPlaceholders;
import ch.andre601.advancedserverlist.velocity.objects.placeholders.VelocityProxyPlaceholders;
import ch.andre601.advancedserverlist.velocity.objects.placeholders.VelocityServerPlaceholders;
import com.alessiodp.libby.Library;
import com.alessiodp.libby.VelocityLibraryManager;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import com.google.inject.Inject;
import com.velocitypowered.api.command.CommandMeta;
import com.velocitypowered.api.event.Subscribe;
@@ -46,6 +49,7 @@ import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
import com.velocitypowered.api.plugin.annotation.DataDirectory;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ProxyServer;
import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.proxy.server.ServerPing;
import com.velocitypowered.api.scheduler.ScheduledTask;
@@ -67,6 +71,7 @@ import java.util.concurrent.TimeUnit;
public class VelocityCore implements PluginCore<Favicon>{
public static final MinecraftChannelIdentifier ASL_IDENTIFIER = MinecraftChannelIdentifier.from("advancedserverlist:action");
private final Map<String, ServerPing> fetchedServers = new ConcurrentHashMap<>();
private final PluginLogger pluginLogger;
@@ -85,6 +90,7 @@ public class VelocityCore implements PluginCore<Favicon>{
@Inject
public VelocityCore(ProxyServer proxy, @DataDirectory Path path, Metrics.Factory metrics){
proxy.getChannelRegistrar().register(ASL_IDENTIFIER);
ComponentLogger logger = ComponentLogger.logger("AdvancedServerList");
this.pluginLogger = new VelocityLogger(this, logger);
this.logger = logger;
@@ -120,8 +126,9 @@ public class VelocityCore implements PluginCore<Favicon>{
@Override
public void loadEvents(){
new JoinEvent(this);
new PingEvent(this);
new JoinListener(this);
new PingListener(this);
new PluginMessageListener(this);
}
@Override
@@ -246,6 +253,11 @@ public class VelocityCore implements PluginCore<Favicon>{
return;
fetchedServers.put(server.getServerInfo().getName(), ping);
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("findPlugins");
server.sendPluginMessage(ASL_IDENTIFIER, out.toByteArray());
}));
}
}
@@ -33,11 +33,11 @@ import com.velocitypowered.api.proxy.Player;
import java.net.InetSocketAddress;
public class JoinEvent{
public class JoinListener{
private final VelocityCore plugin;
public JoinEvent(VelocityCore plugin){
public JoinListener(VelocityCore plugin){
this.plugin = plugin;
plugin.getProxy().getEventManager().register(plugin, this);
}
@@ -33,11 +33,11 @@ import com.velocitypowered.api.event.PostOrder;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.proxy.ProxyPingEvent;
public class PingEvent{
public class PingListener{
private final VelocityCore plugin;
public PingEvent(VelocityCore plugin){
public PingListener(VelocityCore plugin){
this.plugin = plugin;
plugin.getProxy().getEventManager().register(plugin, this);
}
@@ -0,0 +1,40 @@
package ch.andre601.advancedserverlist.velocity.listeners;
import ch.andre601.advancedserverlist.core.objects.PluginMessageUtil;
import ch.andre601.advancedserverlist.velocity.VelocityCore;
import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteStreams;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.connection.PluginMessageEvent;
import com.velocitypowered.api.proxy.ServerConnection;
public class PluginMessageListener{
public PluginMessageListener(VelocityCore plugin){
plugin.getProxy().getEventManager().register(plugin, this);
}
@Subscribe
public void onPluginMessage(PluginMessageEvent event){
if(!(event.getSource() instanceof ServerConnection))
return;
if(event.getIdentifier() != VelocityCore.ASL_IDENTIFIER)
return;
ByteArrayDataInput input = ByteStreams.newDataInput(event.getData());
String subChannel = input.readUTF();
switch(subChannel){
case "hasPlugin" -> {
String serverName = input.readUTF();
PluginMessageUtil.get().addServer(serverName);
}
case "parsed" -> {
String uuid = input.readUTF();
String parsed = input.readUTF();
PluginMessageUtil.get().queue(uuid, parsed, true);
}
}
}
}
@@ -29,17 +29,18 @@ import ch.andre601.advancedserverlist.api.events.GenericServerListEvent;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
import ch.andre601.advancedserverlist.core.compat.maintenance.MaintenanceUtil;
import ch.andre601.advancedserverlist.core.compat.papi.PAPIUtil;
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
import ch.andre601.advancedserverlist.core.interfaces.events.GenericEventWrapper;
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
import ch.andre601.advancedserverlist.core.objects.PluginMessageUtil;
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
import ch.andre601.advancedserverlist.velocity.VelocityCore;
import ch.andre601.advancedserverlist.velocity.objects.impl.VelocityPlayerImpl;
import ch.andre601.advancedserverlist.velocity.objects.impl.VelocityProxyImpl;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import com.velocitypowered.api.event.proxy.ProxyPingEvent;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.proxy.server.ServerPing;
import com.velocitypowered.api.util.Favicon;
@@ -177,25 +178,25 @@ public class VelocityEventWrapper implements GenericEventWrapper<Favicon, Veloci
@Override
public String parsePAPIPlaceholders(String text, VelocityPlayerImpl player){
if(!plugin.getProxy().getPluginManager().isLoaded("papiproxybridge"))
return text;
if(!PAPIUtil.get().isCompatible())
return text;
String server = PAPIUtil.get().getServer();
if(server == null || server.isEmpty())
return text;
RegisteredServer registeredServer = plugin.getProxy().getServer(server).orElse(null);
if(registeredServer == null || registeredServer.getPlayersConnected().isEmpty())
return text;
Player carrier = PAPIUtil.get().getPlayer(registeredServer.getPlayersConnected());
if(carrier == null)
return text;
return PAPIUtil.get().parse(text, carrier.getUniqueId(), player.getUUID());
return PluginMessageUtil.get().getOrExecute(player.getUUID().toString(), text, (uuid, textValue) -> {
List<String> servers = PluginMessageUtil.get().getKnownServers();
if(servers.isEmpty())
return textValue;
RegisteredServer registeredServer = plugin.getProxy().getServer(servers.get(0)).orElse(null);
if(registeredServer == null)
return textValue;
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("parse");
out.writeUTF(uuid);
out.writeUTF(textValue);
registeredServer.sendPluginMessage(VelocityCore.ASL_IDENTIFIER, out.toByteArray());
PluginMessageUtil.get().queue(uuid, textValue, false);
return PluginMessageUtil.get().getOrDefault(uuid, textValue);
});
}
@Override